AutoTest: Use mark and sweep for parsing

This also removes caching from parser and the respective test info
files are gone now as well.

Change-Id: Ibcea68e446dea532d6addd2f16863738e497bca4
Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
Christian Stenger
2016-01-25 13:05:12 +01:00
parent fd4d1c801f
commit 992f9ed222
9 changed files with 122 additions and 639 deletions

View File

@@ -11,7 +11,6 @@ SOURCES += \
testtreemodel.cpp \ testtreemodel.cpp \
testtreeitem.cpp \ testtreeitem.cpp \
testvisitor.cpp \ testvisitor.cpp \
testinfo.cpp \
testcodeparser.cpp \ testcodeparser.cpp \
autotestplugin.cpp \ autotestplugin.cpp \
testrunner.cpp \ testrunner.cpp \
@@ -31,7 +30,6 @@ HEADERS += \
testtreemodel.h \ testtreemodel.h \
testtreeitem.h \ testtreeitem.h \
testvisitor.h \ testvisitor.h \
testinfo.h \
testcodeparser.h \ testcodeparser.h \
autotestplugin.h \ autotestplugin.h \
autotest_global.h \ autotest_global.h \

View File

@@ -40,8 +40,6 @@ QtcPlugin {
"testcodeparser.h", "testcodeparser.h",
"testconfiguration.cpp", "testconfiguration.cpp",
"testconfiguration.h", "testconfiguration.h",
"testinfo.cpp",
"testinfo.h",
"testnavigationwidget.cpp", "testnavigationwidget.cpp",
"testnavigationwidget.h", "testnavigationwidget.h",
"testresult.cpp", "testresult.cpp",

View File

@@ -105,11 +105,6 @@ void AutoTestUnitTests::testCodeParser()
QCOMPARE(m_model->namedQuickTestsCount(), expectedNamedQuickTestsCount); QCOMPARE(m_model->namedQuickTestsCount(), expectedNamedQuickTestsCount);
QCOMPARE(m_model->unnamedQuickTestsCount(), expectedUnnamedQuickTestsCount); QCOMPARE(m_model->unnamedQuickTestsCount(), expectedUnnamedQuickTestsCount);
QCOMPARE(m_model->dataTagsCount(), expectedDataTagsCount); QCOMPARE(m_model->dataTagsCount(), expectedDataTagsCount);
QCOMPARE(m_model->parser()->autoTestsCount(), expectedAutoTestsCount);
QCOMPARE(m_model->parser()->namedQuickTestsCount(), expectedNamedQuickTestsCount);
QCOMPARE(m_model->parser()->unnamedQuickTestsCount(), expectedUnnamedQuickTestsCount);
} }
void AutoTestUnitTests::testCodeParser_data() void AutoTestUnitTests::testCodeParser_data()
@@ -162,12 +157,6 @@ void AutoTestUnitTests::testCodeParserSwitchStartup()
m_isQt4 ? 0 : expectedUnnamedQuickTestsCount.at(i)); m_isQt4 ? 0 : expectedUnnamedQuickTestsCount.at(i));
QCOMPARE(m_model->dataTagsCount(), QCOMPARE(m_model->dataTagsCount(),
expectedDataTagsCount.at(i)); expectedDataTagsCount.at(i));
QCOMPARE(m_model->parser()->autoTestsCount(), expectedAutoTestsCount.at(i));
QCOMPARE(m_model->parser()->namedQuickTestsCount(),
m_isQt4 ? 0 : expectedNamedQuickTestsCount.at(i));
QCOMPARE(m_model->parser()->unnamedQuickTestsCount(),
m_isQt4 ? 0 : expectedUnnamedQuickTestsCount.at(i));
} }
} }
@@ -212,8 +201,6 @@ void AutoTestUnitTests::testCodeParserGTest()
QVERIFY(parserSpy.wait(20000)); QVERIFY(parserSpy.wait(20000));
QCOMPARE(m_model->gtestNamesCount(), 6); QCOMPARE(m_model->gtestNamesCount(), 6);
// 11 == 3 + 2 + 2 + 2 + 1 + 1, see below
QCOMPARE(m_model->parser()->gtestNamesAndSetsCount(), 11);
QMultiMap<QString, int> expectedNamesAndSets; QMultiMap<QString, int> expectedNamesAndSets;
expectedNamesAndSets.insert(QStringLiteral("FactorialTest"), 3); expectedNamesAndSets.insert(QStringLiteral("FactorialTest"), 3);
@@ -233,10 +220,6 @@ void AutoTestUnitTests::testCodeParserGTest()
QCOMPARE(m_model->namedQuickTestsCount(), 0); QCOMPARE(m_model->namedQuickTestsCount(), 0);
QCOMPARE(m_model->unnamedQuickTestsCount(), 0); QCOMPARE(m_model->unnamedQuickTestsCount(), 0);
QCOMPARE(m_model->dataTagsCount(), 0); QCOMPARE(m_model->dataTagsCount(), 0);
QCOMPARE(m_model->parser()->autoTestsCount(), 0);
QCOMPARE(m_model->parser()->namedQuickTestsCount(), 0);
QCOMPARE(m_model->parser()->unnamedQuickTestsCount(), 0);
} }
} // namespace Internal } // namespace Internal

View File

@@ -26,7 +26,6 @@
#include "autotestconstants.h" #include "autotestconstants.h"
#include "autotest_utils.h" #include "autotest_utils.h"
#include "testcodeparser.h" #include "testcodeparser.h"
#include "testinfo.h"
#include "testvisitor.h" #include "testvisitor.h"
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
@@ -84,7 +83,6 @@ TestCodeParser::TestCodeParser(TestTreeModel *parent)
TestCodeParser::~TestCodeParser() TestCodeParser::~TestCodeParser()
{ {
clearCache();
} }
void TestCodeParser::setState(State state) void TestCodeParser::setState(State state)
@@ -145,7 +143,7 @@ void TestCodeParser::updateTestTree()
m_fullUpdatePostponed = false; m_fullUpdatePostponed = false;
clearCache(); emit aboutToPerformFullParse();
qCDebug(LOG) << "calling scanForTests (updateTestTree)"; qCDebug(LOG) << "calling scanForTests (updateTestTree)";
scanForTests(); scanForTests();
} }
@@ -488,7 +486,7 @@ static TestTreeItem *constructGTestTreeItem(const QString &filePath, const GTest
static bool parsingHasFailed; static bool parsingHasFailed;
void performParse(QFutureInterface<void> &futureInterface, const QStringList &list, void performParse(QFutureInterface<void> &futureInterface, const QStringList &list,
const QMap<QString, TestCodeParser::ReferencingInfo> &referencingFiles, const QMap<QString, QString> &referencingFiles,
TestCodeParser *testCodeParser) TestCodeParser *testCodeParser)
{ {
int progressValue = 0; int progressValue = 0;
@@ -501,8 +499,9 @@ void performParse(QFutureInterface<void> &futureInterface, const QStringList &li
if (snapshot.contains(file)) { if (snapshot.contains(file)) {
CPlusPlus::Document::Ptr doc = snapshot.find(file).value(); CPlusPlus::Document::Ptr doc = snapshot.find(file).value();
futureInterface.setProgressValue(++progressValue); futureInterface.setProgressValue(++progressValue);
const QString &referencingFile = referencingFiles.value(file);
testCodeParser->checkDocumentForTestCode(doc, testCodeParser->checkDocumentForTestCode(doc,
referencingFiles.value(file).referencingFile); list.contains(referencingFile) ? QString() : referencingFile);
} else { } else {
parsingHasFailed |= (CppTools::ProjectFile::classify(file) parsingHasFailed |= (CppTools::ProjectFile::classify(file)
!= CppTools::ProjectFile::Unclassified); != CppTools::ProjectFile::Unclassified);
@@ -520,10 +519,8 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr document,
QList<CppTools::ProjectPart::Ptr> projParts = modelManager->projectPart(fileName); QList<CppTools::ProjectPart::Ptr> projParts = modelManager->projectPart(fileName);
if (projParts.size()) if (projParts.size())
if (!projParts.at(0)->selectedForBuilding) { if (!projParts.at(0)->selectedForBuilding)
removeTestsIfNecessary(fileName);
return; return;
}
if (includesQtQuickTest(document, modelManager)) { if (includesQtQuickTest(document, modelManager)) {
handleQtQuickTest(document); handleQtQuickTest(document);
@@ -540,6 +537,8 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr document,
if (declaringDoc.isNull()) if (declaringDoc.isNull())
return; return;
const bool hasReferencingFile = declaringDoc->fileName() != document->fileName();
TestVisitor visitor(testCaseName); TestVisitor visitor(testCaseName);
visitor.accept(declaringDoc->globalNamespace()); visitor.accept(declaringDoc->globalNamespace());
const QMap<QString, TestCodeLocationAndType> testFunctions = visitor.privateSlots(); const QMap<QString, TestCodeLocationAndType> testFunctions = visitor.privateSlots();
@@ -547,14 +546,16 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr document,
QMap<QString, TestCodeLocationList> dataTags = QMap<QString, TestCodeLocationList> dataTags =
checkForDataTags(declaringDoc->fileName(), testFunctions); checkForDataTags(declaringDoc->fileName(), testFunctions);
if (declaringDoc->fileName() != document->fileName()) if (hasReferencingFile)
dataTags.unite(checkForDataTags(document->fileName(), testFunctions)); dataTags.unite(checkForDataTags(document->fileName(), testFunctions));
TestTreeItem *item = constructTestTreeItem(declaringDoc->fileName(), QString(), TestTreeItem *item = constructTestTreeItem(declaringDoc->fileName(), QString(),
testCaseName, line, column, testFunctions, testCaseName, line, column, testFunctions,
dataTags); dataTags);
if (hasReferencingFile)
item->setReferencingFile(fileName);
updateModelAndCppDocMap(document, declaringDoc->fileName(), item); emit testItemCreated(item, TestTreeModel::AutoTest);
return; return;
} }
} }
@@ -570,12 +571,8 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr document,
// maybe file is only a referenced file // maybe file is only a referenced file
if (!referencingFile.isEmpty()) { if (!referencingFile.isEmpty()) {
CPlusPlus::Snapshot snapshot = modelManager->snapshot(); CPlusPlus::Snapshot snapshot = modelManager->snapshot();
if (snapshot.contains(referencingFile)) { if (snapshot.contains(referencingFile))
checkDocumentForTestCode(snapshot.find(referencingFile).value()); checkDocumentForTestCode(snapshot.find(referencingFile).value());
} else { // no referencing file too, so this test case is no more a test case
m_referencingFiles.remove(fileName);
emit testItemsRemoved(fileName, TestTreeModel::AutoTest);
}
} }
} }
@@ -602,19 +599,28 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr document)
const TestCodeLocationAndType tcLocationAndType = qmlVisitor.testCaseLocation(); const TestCodeLocationAndType tcLocationAndType = qmlVisitor.testCaseLocation();
const QMap<QString, TestCodeLocationAndType> testFunctions = qmlVisitor.testFunctions(); const QMap<QString, TestCodeLocationAndType> testFunctions = qmlVisitor.testFunctions();
TestTreeItem *testTreeItem;
if (testCaseName.isEmpty()) { if (testCaseName.isEmpty()) {
updateUnnamedQuickTests(qmlJSDoc->fileName(), cppFileName, testFunctions); testTreeItem = new TestTreeItem(QString(), QString(), TestTreeItem::TestClass);
continue;
} // end of handling test cases without name property
// construct new/modified TestTreeItem foreach (const QString &functionName, testFunctions.keys()) {
TestTreeItem *testTreeItem const TestCodeLocationAndType locationAndType = testFunctions.value(functionName);
= constructTestTreeItem(tcLocationAndType.m_name, cppFileName, testCaseName, TestTreeItem *testFunction = new TestTreeItem(functionName, locationAndType.m_name,
tcLocationAndType.m_line, tcLocationAndType.m_column, locationAndType.m_type);
testFunctions); testFunction->setLine(locationAndType.m_line);
testFunction->setColumn(locationAndType.m_column);
testFunction->setMainFile(cppFileName);
testFunction->setReferencingFile(cppFileName);
testTreeItem->appendChild(testFunction);
}
// update model and internal map } else {
updateModelAndQuickDocMap(qmlJSDoc, cppFileName, testTreeItem); testTreeItem = constructTestTreeItem(tcLocationAndType.m_name, cppFileName,
testCaseName, tcLocationAndType.m_line,
tcLocationAndType.m_column, testFunctions);
testTreeItem->setReferencingFile(cppFileName);
}
emit testItemCreated(testTreeItem, TestTreeModel::QuickTest);
} }
} }
@@ -629,7 +635,17 @@ void TestCodeParser::handleGTest(const QString &filePath)
visitor.accept(ast); visitor.accept(ast);
QMap<GTestCaseSpec, TestCodeLocationList> result = visitor.gtestFunctions(); QMap<GTestCaseSpec, TestCodeLocationList> result = visitor.gtestFunctions();
updateGTests(document, result); QString proFile;
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(filePath);
if (ppList.size())
proFile = ppList.at(0)->projectFile;
foreach (const GTestCaseSpec &testSpec, result.keys()) {
TestTreeItem *item = constructGTestTreeItem(filePath, testSpec, proFile,
result.value(testSpec));
emit testItemCreated(item, TestTreeModel::GoogleTest);
}
} }
void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document) void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document)
@@ -672,26 +688,15 @@ void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document)
return; return;
} }
const CPlusPlus::Snapshot snapshot = CppTools::CppModelManager::instance()->snapshot(); const CPlusPlus::Snapshot snapshot = CppTools::CppModelManager::instance()->snapshot();
if (m_referencingFiles.contains(fileName)) { QMap<QString, QString> referencingFiles = m_model->referencingFiles();
const ReferencingInfo &refInfo = m_referencingFiles.value(fileName); if (referencingFiles.contains(fileName)) {
if (refInfo.type == TestTreeModel::QuickTest const QString &referencingFile = referencingFiles.value(fileName);
&& snapshot.contains(refInfo.referencingFile)) { if (!referencingFile.isEmpty() && snapshot.contains(referencingFile)) {
if (!refInfo.referencingFile.isEmpty()) { qCDebug(LOG) << "calling scanForTests with cached referencing files"
qCDebug(LOG) << "calling scanForTests with cached referencing files" << "(onQmlDocumentUpdated)";
<< "(onQmlDocumentUpdated)"; scanForTests(QStringList(referencingFile));
scanForTests(QStringList(refInfo.referencingFile));
}
} }
} }
if (m_unnamedQuickDocList.size() == 0)
return;
// special case of having unnamed TestCases
const QString &mainFile = m_model->getMainFileForUnnamedQuickTest(fileName);
if (!mainFile.isEmpty() && snapshot.contains(mainFile)) {
qCDebug(LOG) << "calling scanForTests with mainfile (onQmlDocumentUpdated)";
scanForTests(QStringList(mainFile));
}
} }
void TestCodeParser::onStartupProjectChanged(ProjectExplorer::Project *) void TestCodeParser::onStartupProjectChanged(ProjectExplorer::Project *)
@@ -699,7 +704,7 @@ void TestCodeParser::onStartupProjectChanged(ProjectExplorer::Project *)
if (m_parserState == FullParse || m_parserState == PartialParse) { if (m_parserState == FullParse || m_parserState == PartialParse) {
Core::ProgressManager::instance()->cancelTasks(Constants::TASK_PARSE); Core::ProgressManager::instance()->cancelTasks(Constants::TASK_PARSE);
} else { } else {
clearCache(); emit aboutToPerformFullParse();
emitUpdateTestTree(); emitUpdateTestTree();
} }
} }
@@ -714,12 +719,6 @@ void TestCodeParser::onProjectPartsUpdated(ProjectExplorer::Project *project)
emitUpdateTestTree(); emitUpdateTestTree();
} }
void TestCodeParser::removeFiles(const QStringList &files)
{
foreach (const QString &file, files)
removeTestsIfNecessary(file);
}
bool TestCodeParser::postponed(const QStringList &fileList) bool TestCodeParser::postponed(const QStringList &fileList)
{ {
switch (m_parserState) { switch (m_parserState) {
@@ -786,13 +785,20 @@ void TestCodeParser::scanForTests(const QStringList &fileList)
} }
parsingHasFailed = false; parsingHasFailed = false;
QMap<QString, QString> referencingFiles = m_model->referencingFiles();
if (isSmallChange) { // no need to do this async or should we do this always async? if (isSmallChange) { // no need to do this async or should we do this always async?
foreach (const QString &filePath, list)
m_model->markForRemoval(filePath);
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
CPlusPlus::Snapshot snapshot = cppMM->snapshot(); CPlusPlus::Snapshot snapshot = cppMM->snapshot();
foreach (const QString &file, list) { foreach (const QString &file, list) {
if (snapshot.contains(file)) { if (snapshot.contains(file)) {
CPlusPlus::Document::Ptr doc = snapshot.find(file).value(); CPlusPlus::Document::Ptr doc = snapshot.find(file).value();
checkDocumentForTestCode(doc, m_referencingFiles.value(file).referencingFile); const QString &referencingFile = referencingFiles.value(file);
checkDocumentForTestCode(doc, list.contains(referencingFile) ? QString()
: referencingFile);
} else { } else {
parsingHasFailed |= (CppTools::ProjectFile::classify(file) parsingHasFailed |= (CppTools::ProjectFile::classify(file)
!= CppTools::ProjectFile::Unclassified); != CppTools::ProjectFile::Unclassified);
@@ -802,7 +808,9 @@ void TestCodeParser::scanForTests(const QStringList &fileList)
return; return;
} }
QFuture<void> future = Utils::runAsync<void>(&performParse, list, m_referencingFiles, this); m_model->markAllForRemoval();
QFuture<void> future = Utils::runAsync<void>(&performParse, list, referencingFiles, this);
Core::FutureProgress *progress Core::FutureProgress *progress
= Core::ProgressManager::addTask(future, isFullParse ? tr("Scanning for Tests") = Core::ProgressManager::addTask(future, isFullParse ? tr("Scanning for Tests")
: tr("Refreshing Tests List"), : tr("Refreshing Tests List"),
@@ -813,53 +821,6 @@ void TestCodeParser::scanForTests(const QStringList &fileList)
emit parsingStarted(); emit parsingStarted();
} }
void TestCodeParser::clearCache()
{
m_referencingFiles.clear();
m_unnamedQuickDocList.clear();
m_gtestDocList.clear();
emit cacheCleared();
}
void TestCodeParser::removeTestsIfNecessary(const QString &fileName)
{
// check if this file was listed before and remove if necessary (switched config,...)
if (m_referencingFiles.contains(fileName)
&& m_referencingFiles.value(fileName).type == TestTreeModel::AutoTest) {
m_referencingFiles.remove(fileName);
emit testItemsRemoved(fileName, TestTreeModel::AutoTest);
} else if (m_referencingFiles.contains(fileName)
&& m_referencingFiles.value(fileName).type == TestTreeModel::GoogleTest) {
m_referencingFiles.remove(fileName);
emit testItemsRemoved(fileName, TestTreeModel::GoogleTest);
} else { // handle Qt Quick Tests
QList<QString> toBeRemoved;
foreach (const QString &file, m_referencingFiles.keys()) {
if (file == fileName
&& m_referencingFiles.value(file).type == TestTreeModel::QuickTest) {
toBeRemoved.append(file);
continue;
}
const ReferencingInfo &refInfo = m_referencingFiles.value(file);
if (refInfo.type == TestTreeModel::QuickTest && refInfo.referencingFile == fileName)
toBeRemoved.append(file);
}
foreach (const QString &file, toBeRemoved) {
m_referencingFiles.remove(file);
emit testItemsRemoved(file, TestTreeModel::QuickTest);
}
// unnamed Quick Tests must be handled separately
if (fileName.endsWith(QLatin1String(".qml"))) {
removeUnnamedQuickTestsByName(fileName);
} else {
QSet<QString> filePaths;
m_model->qmlFilesForMainFile(fileName, &filePaths);
foreach (const QString &file, filePaths)
removeUnnamedQuickTestsByName(file);
}
}
}
void TestCodeParser::onTaskStarted(Core::Id type) void TestCodeParser::onTaskStarted(Core::Id type)
{ {
if (type == CppTools::Constants::TASK_INDEX) if (type == CppTools::Constants::TASK_INDEX)
@@ -936,175 +897,5 @@ void TestCodeParser::onPartialParsingFinished()
} }
} }
void TestCodeParser::updateUnnamedQuickTests(const QString &fileName, const QString &mainFile,
const QMap<QString, TestCodeLocationAndType> &functions)
{
// if this test case was named before remove it
m_referencingFiles.remove(fileName);
emit testItemsRemoved(fileName, TestTreeModel::QuickTest);
removeUnnamedQuickTestsByName(fileName);
foreach (const QString &functionName, functions.keys()) {
UnnamedQuickTestInfo info(functionName, fileName);
m_unnamedQuickDocList.append(info);
}
emit unnamedQuickTestsUpdated(mainFile, functions);
}
void TestCodeParser::updateModelAndCppDocMap(CPlusPlus::Document::Ptr document,
const QString &declaringFile, TestTreeItem *testItem)
{
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
const QString fileName = document->fileName();
const QString testCaseName = testItem->name();
QString proFile;
const QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(fileName);
if (ppList.size())
proFile = ppList.at(0)->projectFile;
if (m_referencingFiles.contains(fileName)
&& m_referencingFiles.value(fileName).type == TestTreeModel::AutoTest) {
QStringList files = { fileName };
if (fileName != declaringFile)
files << declaringFile;
foreach (const QString &file, files) {
const bool setReferencingFile = (files.size() == 2 && file == declaringFile);
ReferencingInfo testInfo;
if (setReferencingFile) {
testInfo.referencingFile = fileName;
testItem->setReferencingFile(fileName);
}
testInfo.type = TestTreeModel::AutoTest;
m_referencingFiles.insert(file, testInfo);
}
emit testItemModified(testItem, TestTreeModel::AutoTest, files);
} else {
if (declaringFile != fileName)
testItem->setReferencingFile(fileName);
emit testItemCreated(testItem, TestTreeModel::AutoTest);
ReferencingInfo testInfo;
testInfo.type = TestTreeModel::AutoTest;
m_referencingFiles.insert(fileName, testInfo);
if (declaringFile != fileName) {
testInfo.referencingFile = fileName;
m_referencingFiles.insert(declaringFile, testInfo);
}
}
}
void TestCodeParser::updateModelAndQuickDocMap(QmlJS::Document::Ptr document,
const QString &referencingFile,
TestTreeItem *testItem)
{
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
const QString fileName = document->fileName();
QString proFile;
QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(referencingFile);
if (ppList.size())
proFile = ppList.at(0)->projectFile;
if (m_referencingFiles.contains(fileName)
&& m_referencingFiles.value(fileName).type == TestTreeModel::QuickTest) {
ReferencingInfo testInfo;
testInfo.referencingFile = referencingFile;
testInfo.type = TestTreeModel::QuickTest;
testItem->setReferencingFile(referencingFile);
emit testItemModified(testItem, TestTreeModel::QuickTest, { fileName });
m_referencingFiles.insert(fileName, testInfo);
} else {
// if it was formerly unnamed remove the respective items
removeUnnamedQuickTestsByName(fileName);
const QString &filePath = testItem->filePath();
ReferencingInfo testInfo;
testInfo.referencingFile = referencingFile;
testInfo.type = TestTreeModel::QuickTest;
testItem->setReferencingFile(referencingFile);
emit testItemCreated(testItem, TestTreeModel::QuickTest);
m_referencingFiles.insert(filePath, testInfo);
}
}
void TestCodeParser::updateGTests(const CPlusPlus::Document::Ptr &doc,
const QMap<GTestCaseSpec, TestCodeLocationList> &tests)
{
const QString &fileName = doc->fileName();
removeGTestsByName(fileName);
QString proFile;
const CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
QList<CppTools::ProjectPart::Ptr> ppList = cppMM->projectPart(fileName);
if (ppList.size())
proFile = ppList.at(0)->projectFile;
foreach (const GTestCaseSpec &testSpec, tests.keys()) {
TestTreeItem *item = constructGTestTreeItem(fileName, testSpec, proFile, tests.value(testSpec));
ReferencingInfo testInfo;
testInfo.type = TestTreeModel::GoogleTest;
foreach (const TestCodeLocationAndType &testSet, tests.value(testSpec)) {
GTestInfo gtestInfo(testSpec.testCaseName, testSet.m_name, fileName);
if (testSet.m_state & TestTreeItem::Disabled)
gtestInfo.setEnabled(false);
m_gtestDocList.append(gtestInfo);
}
emit testItemCreated(item, TestTreeModel::GoogleTest);
m_referencingFiles.insert(fileName, testInfo);
}
}
void TestCodeParser::removeUnnamedQuickTestsByName(const QString &fileName)
{
for (int i = m_unnamedQuickDocList.size() - 1; i >= 0; --i) {
if (m_unnamedQuickDocList.at(i).fileName() == fileName)
m_unnamedQuickDocList.removeAt(i);
}
emit unnamedQuickTestsRemoved(fileName);
}
void TestCodeParser::removeGTestsByName(const QString &fileName)
{
for (int i = m_gtestDocList.size() - 1; i >= 0; --i)
if (m_gtestDocList.at(i).fileName() == fileName)
m_gtestDocList.removeAt(i);
emit gTestsRemoved(fileName);
}
#ifdef WITH_TESTS
int TestCodeParser::autoTestsCount() const
{
int count = 0;
foreach (const QString &file, m_referencingFiles.keys()) {
const ReferencingInfo &refInfo = m_referencingFiles.value(file);
if (refInfo.type == TestTreeModel::AutoTest && refInfo.referencingFile.isEmpty())
++count;
}
return count;
}
int TestCodeParser::namedQuickTestsCount() const
{
int count = 0;
foreach (const QString &file, m_referencingFiles.keys()) {
const ReferencingInfo &refInfo = m_referencingFiles.value(file);
if (refInfo.type == TestTreeModel::QuickTest)
++count;
}
return count;
}
int TestCodeParser::unnamedQuickTestsCount() const
{
return m_unnamedQuickDocList.size();
}
int TestCodeParser::gtestNamesAndSetsCount() const
{
return m_gtestDocList.size();
}
#endif
} // namespace Internal } // namespace Internal
} // namespace Autotest } // namespace Autotest

View File

@@ -44,8 +44,6 @@ namespace Autotest {
namespace Internal { namespace Internal {
struct TestCodeLocationAndType; struct TestCodeLocationAndType;
class UnnamedQuickTestInfo;
class GTestInfo;
struct GTestCaseSpec; struct GTestCaseSpec;
class TestCodeParser : public QObject class TestCodeParser : public QObject
@@ -65,29 +63,9 @@ public:
State state() const { return m_parserState; } State state() const { return m_parserState; }
void setDirty() { m_dirty = true; } void setDirty() { m_dirty = true; }
#ifdef WITH_TESTS
int autoTestsCount() const;
int namedQuickTestsCount() const;
int unnamedQuickTestsCount() const;
int gtestNamesAndSetsCount() const;
#endif
// FIXME remove me again
struct ReferencingInfo
{
QString referencingFile;
TestTreeModel::Type type;
};
signals: signals:
void cacheCleared(); void aboutToPerformFullParse();
void testItemCreated(TestTreeItem *item, TestTreeModel::Type type); void testItemCreated(TestTreeItem *item, TestTreeModel::Type type);
void testItemModified(TestTreeItem *tItem, TestTreeModel::Type type, const QStringList &file);
void testItemsRemoved(const QString &filePath, TestTreeModel::Type type);
void unnamedQuickTestsUpdated(const QString &mainFile,
const QMap<QString, TestCodeLocationAndType> &functions);
void unnamedQuickTestsRemoved(const QString &filePath);
void gTestsRemoved(const QString &filePath);
void parsingStarted(); void parsingStarted();
void parsingFinished(); void parsingFinished();
void parsingFailed(); void parsingFailed();
@@ -105,34 +83,18 @@ public slots:
void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document); void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document);
void onStartupProjectChanged(ProjectExplorer::Project *); void onStartupProjectChanged(ProjectExplorer::Project *);
void onProjectPartsUpdated(ProjectExplorer::Project *project); void onProjectPartsUpdated(ProjectExplorer::Project *project);
void removeFiles(const QStringList &files);
private: private:
bool postponed(const QStringList &fileList); bool postponed(const QStringList &fileList);
void scanForTests(const QStringList &fileList = QStringList()); void scanForTests(const QStringList &fileList = QStringList());
void clearCache();
void removeTestsIfNecessary(const QString &fileName);
void onTaskStarted(Core::Id type); void onTaskStarted(Core::Id type);
void onAllTasksFinished(Core::Id type); void onAllTasksFinished(Core::Id type);
void onFinished(); void onFinished();
void onPartialParsingFinished(); void onPartialParsingFinished();
void updateUnnamedQuickTests(const QString &fileName, const QString &mainFile,
const QMap<QString, TestCodeLocationAndType> &functions);
void updateModelAndCppDocMap(CPlusPlus::Document::Ptr document,
const QString &declaringFile, TestTreeItem *testItem);
void updateModelAndQuickDocMap(QmlJS::Document::Ptr document,
const QString &referencingFile, TestTreeItem *testItem);
void updateGTests(const CPlusPlus::Document::Ptr &doc,
const QMap<GTestCaseSpec, TestCodeLocationList> &tests);
void removeUnnamedQuickTestsByName(const QString &fileName);
void removeGTestsByName(const QString &fileName);
TestTreeModel *m_model; TestTreeModel *m_model;
QMap<QString, ReferencingInfo> m_referencingFiles;
QList<UnnamedQuickTestInfo> m_unnamedQuickDocList;
QList<GTestInfo> m_gtestDocList;
bool m_codeModelParsing; bool m_codeModelParsing;
bool m_fullUpdatePostponed; bool m_fullUpdatePostponed;
bool m_partialUpdatePostponed; bool m_partialUpdatePostponed;

View File

@@ -1,46 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "testinfo.h"
namespace Autotest {
namespace Internal {
UnnamedQuickTestInfo::UnnamedQuickTestInfo(const QString &function, const QString &fileName)
: m_function(function),
m_fileName(fileName)
{
}
GTestInfo::GTestInfo(const QString &caseName, const QString &setName, const QString &file)
: m_caseName(caseName),
m_setName(setName),
m_fileName(file),
m_enabled(true)
{
}
} // namespace Internal
} // namespace Autotest

View File

@@ -1,73 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef TESTINFO_H
#define TESTINFO_H
#include <QStringList>
namespace Autotest {
namespace Internal {
class UnnamedQuickTestInfo {
public:
explicit UnnamedQuickTestInfo(const QString &function = QString(),
const QString& fileName = QString());
~UnnamedQuickTestInfo() {}
const QString function() const { return m_function; }
void setFunction(const QString &function) { m_function = function; }
const QString fileName() const { return m_fileName; }
void setFileName(const QString &fileName) { m_fileName = fileName; }
private:
QString m_function;
QString m_fileName;
};
class GTestInfo {
public:
explicit GTestInfo(const QString &caseName, const QString &setName, const QString &file);
const QString caseName() const { return m_caseName; }
void setCaseName(const QString &caseName) { m_caseName = caseName; }
const QString setName() const { return m_setName; }
void setSetName(const QString &setName) { m_setName = setName; }
const QString fileName() const { return m_fileName; }
void setFileName(const QString &fileName) { m_fileName = fileName; }
bool isEnabled() const { return m_enabled; }
void setEnabled(bool enabled) { m_enabled = enabled; }
private:
QString m_caseName;
QString m_setName;
QString m_fileName;
bool m_enabled;
};
} // namespace Internal
} // namespace Autotest
#endif // TESTINFO_H

View File

@@ -86,33 +86,14 @@ TestTreeModel::TestTreeModel(QObject *parent) :
rootItem()->appendChild(m_quickTestRootItem); rootItem()->appendChild(m_quickTestRootItem);
rootItem()->appendChild(m_googleTestRootItem); rootItem()->appendChild(m_googleTestRootItem);
connect(m_parser, &TestCodeParser::cacheCleared, this, connect(m_parser, &TestCodeParser::aboutToPerformFullParse, this,
&TestTreeModel::removeAllTestItems, Qt::QueuedConnection); &TestTreeModel::removeAllTestItems, Qt::QueuedConnection);
connect(m_parser, &TestCodeParser::testItemCreated, connect(m_parser, &TestCodeParser::testItemCreated,
this, &TestTreeModel::addTestTreeItem, Qt::QueuedConnection); this, &TestTreeModel::addTestTreeItem, Qt::QueuedConnection);
connect(m_parser, &TestCodeParser::testItemModified, connect(m_parser, &TestCodeParser::parsingFinished,
this, &TestTreeModel::modifyTestTreeItem, Qt::QueuedConnection); this, &TestTreeModel::sweep, Qt::QueuedConnection);
connect(m_parser, &TestCodeParser::testItemsRemoved, connect(m_parser, &TestCodeParser::parsingFailed,
this, &TestTreeModel::removeTestTreeItems, Qt::QueuedConnection); this, &TestTreeModel::sweep, Qt::QueuedConnection);
connect(m_parser, &TestCodeParser::unnamedQuickTestsUpdated,
this, &TestTreeModel::updateUnnamedQuickTest, Qt::QueuedConnection);
connect(m_parser, &TestCodeParser::unnamedQuickTestsRemoved,
this, &TestTreeModel::removeUnnamedQuickTests, Qt::QueuedConnection);
connect(m_parser, &TestCodeParser::gTestsRemoved,
this, &TestTreeModel::removeGTests, Qt::QueuedConnection);
// CppTools::CppModelManagerInterface *cppMM = CppTools::CppModelManagerInterface::instance();
// if (cppMM) {
// // replace later on by
// // cppMM->registerAstProcessor([this](const CplusPlus::Document::Ptr &doc,
// // const CPlusPlus::Snapshot &snapshot) {
// // checkForQtTestStuff(doc, snapshot);
// // });
// connect(cppMM, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
// this, SLOT(checkForQtTestStuff(CPlusPlus::Document::Ptr)),
// Qt::DirectConnection);
// }
} }
static TestTreeModel *m_instance = 0; static TestTreeModel *m_instance = 0;
@@ -148,7 +129,7 @@ void TestTreeModel::enableParsing()
connect(cppMM, &CppTools::CppModelManager::documentUpdated, connect(cppMM, &CppTools::CppModelManager::documentUpdated,
m_parser, &TestCodeParser::onCppDocumentUpdated, Qt::QueuedConnection); m_parser, &TestCodeParser::onCppDocumentUpdated, Qt::QueuedConnection);
connect(cppMM, &CppTools::CppModelManager::aboutToRemoveFiles, connect(cppMM, &CppTools::CppModelManager::aboutToRemoveFiles,
m_parser, &TestCodeParser::removeFiles, Qt::QueuedConnection); this, &TestTreeModel::removeFiles, Qt::QueuedConnection);
connect(cppMM, &CppTools::CppModelManager::projectPartsUpdated, connect(cppMM, &CppTools::CppModelManager::projectPartsUpdated,
m_parser, &TestCodeParser::onProjectPartsUpdated); m_parser, &TestCodeParser::onProjectPartsUpdated);
@@ -156,7 +137,7 @@ void TestTreeModel::enableParsing()
connect(qmlJsMM, &QmlJS::ModelManagerInterface::documentUpdated, connect(qmlJsMM, &QmlJS::ModelManagerInterface::documentUpdated,
m_parser, &TestCodeParser::onQmlDocumentUpdated, Qt::QueuedConnection); m_parser, &TestCodeParser::onQmlDocumentUpdated, Qt::QueuedConnection);
connect(qmlJsMM, &QmlJS::ModelManagerInterface::aboutToRemoveFiles, connect(qmlJsMM, &QmlJS::ModelManagerInterface::aboutToRemoveFiles,
m_parser, &TestCodeParser::removeFiles, Qt::QueuedConnection); this, &TestTreeModel::removeFiles, Qt::QueuedConnection);
m_connectionsInitialized = true; m_connectionsInitialized = true;
} }
@@ -541,38 +522,6 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item)
return config; return config;
} }
QString TestTreeModel::getMainFileForUnnamedQuickTest(const QString &qmlFile) const
{
const TestTreeItem *unnamed = unnamedQuickTests();
const int count = unnamed ? unnamed->childCount() : 0;
for (int row = 0; row < count; ++row) {
const TestTreeItem *child = unnamed->childItem(row);
if (qmlFile == child->filePath())
return child->mainFile();
}
return QString();
}
void TestTreeModel::qmlFilesForMainFile(const QString &mainFile, QSet<QString> *filePaths) const
{
const TestTreeItem *unnamed = unnamedQuickTests();
if (!unnamed)
return;
for (int row = 0, count = unnamed->childCount(); row < count; ++row) {
const TestTreeItem *child = unnamed->childItem(row);
if (child->mainFile() == mainFile)
filePaths->insert(child->filePath());
}
}
QList<QString> TestTreeModel::getUnnamedQuickTestFunctions() const
{
const TestTreeItem *unnamed = unnamedQuickTests();
if (unnamed)
return unnamed->getChildNames();
return QList<QString>();
}
bool TestTreeModel::hasUnnamedQuickTests() const bool TestTreeModel::hasUnnamedQuickTests() const
{ {
for (int row = 0, count = m_quickTestRootItem->childCount(); row < count; ++row) for (int row = 0, count = m_quickTestRootItem->childCount(); row < count; ++row)
@@ -591,36 +540,11 @@ TestTreeItem *TestTreeModel::unnamedQuickTests() const
return 0; return 0;
} }
void TestTreeModel::removeUnnamedQuickTests(const QString &filePath) void TestTreeModel::removeFiles(const QStringList &files)
{ {
TestTreeItem *unnamedQT = unnamedQuickTests(); foreach (const QString &file, files)
if (!unnamedQT) markForRemoval(file);
return; sweep();
for (int childRow = unnamedQT->childCount() - 1; childRow >= 0; --childRow) {
TestTreeItem *child = unnamedQT->childItem(childRow);
if (filePath == child->filePath())
delete takeItem(child);
}
if (unnamedQT->childCount() == 0)
delete takeItem(unnamedQT);
emit testTreeModelChanged();
}
void TestTreeModel::removeGTests(const QString &filePath)
{
for (int childRow = m_googleTestRootItem->childCount() - 1; childRow >= 0; --childRow) {
TestTreeItem *child = m_googleTestRootItem->childItem(childRow);
for (int grandChildRow = child->childCount() - 1; grandChildRow >= 0; --grandChildRow) {
TestTreeItem *grandChild = child->childItem(grandChildRow);
if (filePath == grandChild->filePath())
delete takeItem(grandChild);
}
if (child->childCount() == 0)
delete takeItem(child);
}
emit testTreeModelChanged();
} }
void TestTreeModel::markAllForRemoval() void TestTreeModel::markAllForRemoval()
@@ -711,80 +635,61 @@ QMap<QString, QString> TestTreeModel::referencingFiles() const
return finder.referencingFiles(); return finder.referencingFiles();
} }
void TestTreeModel::addTestTreeItem(TestTreeItem *item, TestTreeModel::Type type) TestTreeItem *TestTreeModel::findTestTreeItemByContent(TestTreeItem *item, TestTreeItem *parent,
Type type)
{
for (int row = 0, count = parent->childCount(); row < count; ++row) {
TestTreeItem *current = parent->childItem(row);
if (current->name() != item->name())
continue;
switch (type) {
case AutoTest:
if (current->filePath() == item->filePath())
return current;
break;
case QuickTest:
if (current->filePath() == item->filePath() && current->mainFile() == item->mainFile())
return current;
break;
case GoogleTest:
if (current->type() == item->type())
return current;
break;
}
}
return 0;
}
void TestTreeModel::addTestTreeItem(TestTreeItem *item, Type type)
{ {
TestTreeItem *parent = rootItemForType(type); TestTreeItem *parent = rootItemForType(type);
if (type == TestTreeModel::GoogleTest) { TestTreeItem *toBeUpdated = findTestTreeItemByContent(item, parent, type);
// check if there's already an item with the same test name... const int count = item->childCount();
TestTreeItem *toBeUpdated = 0; if (toBeUpdated) {
for (int row = 0, count = parent->childCount(); row < count; ++row) { if (!toBeUpdated->markedForRemoval()) {
TestTreeItem *current = parent->childItem(row); for (int row = 0; row < count; ++row)
if (current->name() == item->name() && current->type() == item->type()) { toBeUpdated->appendChild(new TestTreeItem(*item->childItem(row)));
toBeUpdated = current; } else {
break; for (int childRow = count - 1; childRow >= 0; --childRow) {
TestTreeItem *childItem = item->childItem(childRow);
TestTreeItem *origChild = findTestTreeItemByContent(childItem, toBeUpdated, type);
if (origChild) {
QModelIndex toBeModifiedIndex = indexForItem(origChild);
modifyTestSubtree(toBeModifiedIndex, childItem);
} else {
toBeUpdated->insertChild(qMin(count, toBeUpdated->childCount()),
new TestTreeItem(*childItem));
}
} }
} }
// ...if so we have, to update this one instead of adding a new item delete item;
if (toBeUpdated) {
for (int row = 0, count = item->childCount(); row < count; ++row)
toBeUpdated->appendChild(new TestTreeItem(*item->childItem(row)));
delete item;
} else {
parent->appendChild(item);
}
} else { } else {
parent->appendChild(item); parent->appendChild(item);
} }
emit testTreeModelChanged(); emit testTreeModelChanged();
} }
void TestTreeModel::updateUnnamedQuickTest(const QString &mainFile,
const QMap<QString, TestCodeLocationAndType> &functions)
{
if (functions.isEmpty())
return;
if (!hasUnnamedQuickTests())
addTestTreeItem(new TestTreeItem(QString(), QString(), TestTreeItem::TestClass), QuickTest);
TestTreeItem *unnamed = unnamedQuickTests();
foreach (const QString &functionName, functions.keys()) {
const TestCodeLocationAndType locationAndType = functions.value(functionName);
TestTreeItem *testFunction = new TestTreeItem(functionName, locationAndType.m_name,
locationAndType.m_type);
testFunction->setLine(locationAndType.m_line);
testFunction->setColumn(locationAndType.m_column);
testFunction->setMainFile(mainFile);
unnamed->appendChild(testFunction);
}
}
void TestTreeModel::modifyTestTreeItem(TestTreeItem *item, TestTreeModel::Type type, const QStringList &files)
{
QModelIndex index = rootIndexForType(type);
TestTreeItem *parent = rootItemForType(type);
if (files.isEmpty()) {
if (TestTreeItem *unnamed = unnamedQuickTests()) {
if (unnamed == item) // no need to update or delete
return;
index = indexForItem(unnamed);
modifyTestSubtree(index, item);
}
} else {
for (int row = 0; row < parent->childCount(); ++row) {
if (files.contains(parent->childItem(row)->filePath())) {
index = index.child(row, 0);
modifyTestSubtree(index, item);
break;
}
}
}
// item was created as temporary, destroy it if it won't get destroyed by its parent
if (!item->parent())
delete item;
}
void TestTreeModel::removeAllTestItems() void TestTreeModel::removeAllTestItems()
{ {
m_autoTestRootItem->removeChildren(); m_autoTestRootItem->removeChildren();
@@ -793,21 +698,6 @@ void TestTreeModel::removeAllTestItems()
emit testTreeModelChanged(); emit testTreeModelChanged();
} }
void TestTreeModel::removeTestTreeItems(const QString &filePath, Type type)
{
bool removed = false;
const TestTreeItem *rootItem = rootItemForType(type);
for (int row = rootItem->childCount() - 1; row >= 0; --row) {
TestTreeItem *childItem = rootItem->childItem(row);
if (filePath == childItem->filePath()) {
delete takeItem(childItem);
removed = true;
}
}
if (removed)
emit testTreeModelChanged();
}
TestTreeItem *TestTreeModel::rootItemForType(TestTreeModel::Type type) TestTreeItem *TestTreeModel::rootItemForType(TestTreeModel::Type type)
{ {
switch (type) { switch (type) {
@@ -821,19 +711,6 @@ TestTreeItem *TestTreeModel::rootItemForType(TestTreeModel::Type type)
QTC_ASSERT(false, return 0); 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);
case GoogleTest:
return index(2, 0);
}
QTC_ASSERT(false, return QModelIndex());
}
void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, const TestTreeItem *newItem) void TestTreeModel::modifyTestSubtree(QModelIndex &toBeModifiedIndex, const TestTreeItem *newItem)
{ {
if (!toBeModifiedIndex.isValid()) if (!toBeModifiedIndex.isValid())

View File

@@ -64,9 +64,6 @@ public:
QList<TestConfiguration *> getAllTestCases() const; QList<TestConfiguration *> getAllTestCases() const;
QList<TestConfiguration *> getSelectedTests() const; QList<TestConfiguration *> getSelectedTests() const;
TestConfiguration *getTestConfiguration(const TestTreeItem *item) const; TestConfiguration *getTestConfiguration(const TestTreeItem *item) const;
QString getMainFileForUnnamedQuickTest(const QString &qmlFile) const;
void qmlFilesForMainFile(const QString &mainFile, QSet<QString> *filePaths) const;
QList<QString> getUnnamedQuickTestFunctions() const;
bool hasUnnamedQuickTests() const; bool hasUnnamedQuickTests() const;
#ifdef WITH_TESTS #ifdef WITH_TESTS
@@ -90,18 +87,14 @@ public slots:
private: private:
void addTestTreeItem(TestTreeItem *item, Type type); void addTestTreeItem(TestTreeItem *item, Type type);
void updateUnnamedQuickTest(const QString &mainFile,
const QMap<QString, TestCodeLocationAndType> &functions);
void modifyTestTreeItem(TestTreeItem *item, Type type, const QStringList &file);
void removeAllTestItems(); void removeAllTestItems();
void removeTestTreeItems(const QString &filePath, Type type); void removeFiles(const QStringList &files);
void removeUnnamedQuickTests(const QString &filePath); void markForRemoval(const QString &filePath, Type type);
void removeGTests(const QString &filePath); void sweepChildren(TestTreeItem *item);
bool sweepChildren(TestTreeItem *item); TestTreeItem *findTestTreeItemByContent(TestTreeItem *item, TestTreeItem *parent, Type type);
TestTreeItem *unnamedQuickTests() const; TestTreeItem *unnamedQuickTests() const;
TestTreeItem *rootItemForType(Type type); TestTreeItem *rootItemForType(Type type);
QModelIndex rootIndexForType(Type type);
explicit TestTreeModel(QObject *parent = 0); explicit TestTreeModel(QObject *parent = 0);
void modifyTestSubtree(QModelIndex &toBeModifiedIndex, const TestTreeItem *newItem); void modifyTestSubtree(QModelIndex &toBeModifiedIndex, const TestTreeItem *newItem);