diff options
-rw-r--r-- | plugins/autotest/autotest.pro | 6 | ||||
-rw-r--r-- | plugins/autotest/testcodeparser.cpp | 52 | ||||
-rw-r--r-- | plugins/autotest/testconfiguration.cpp | 5 | ||||
-rw-r--r-- | plugins/autotest/testconfiguration.h | 3 | ||||
-rw-r--r-- | plugins/autotest/testresultspane.cpp | 4 | ||||
-rw-r--r-- | plugins/autotest/testrunner.cpp | 8 | ||||
-rw-r--r-- | plugins/autotest/testtreeitem.cpp | 58 | ||||
-rw-r--r-- | plugins/autotest/testtreeitem.h | 8 | ||||
-rw-r--r-- | plugins/autotest/testtreeitemdelegate.cpp | 69 | ||||
-rw-r--r-- | plugins/autotest/testtreeitemdelegate.h | 41 | ||||
-rw-r--r-- | plugins/autotest/testtreemodel.cpp | 132 | ||||
-rw-r--r-- | plugins/autotest/testtreemodel.h | 3 | ||||
-rw-r--r-- | plugins/autotest/testtreeview.cpp | 2 | ||||
-rw-r--r-- | plugins/autotest/testvisitor.cpp | 36 | ||||
-rw-r--r-- | plugins/autotest/testvisitor.h | 17 |
15 files changed, 353 insertions, 91 deletions
diff --git a/plugins/autotest/autotest.pro b/plugins/autotest/autotest.pro index 566c6131d1..6d2423bdd7 100644 --- a/plugins/autotest/autotest.pro +++ b/plugins/autotest/autotest.pro @@ -21,7 +21,8 @@ SOURCES += \ testresult.cpp \ testresultspane.cpp \ testresultmodel.cpp \ - testresultdelegate.cpp + testresultdelegate.cpp \ + testtreeitemdelegate.cpp HEADERS += \ testtreeview.h \ @@ -38,7 +39,8 @@ HEADERS += \ testresult.h \ testresultspane.h \ testresultmodel.h \ - testresultdelegate.h + testresultdelegate.h \ + testtreeitemdelegate.h RESOURCES += \ autotest.qrc diff --git a/plugins/autotest/testcodeparser.cpp b/plugins/autotest/testcodeparser.cpp index 9d4f41af06..240bb418d5 100644 --- a/plugins/autotest/testcodeparser.cpp +++ b/plugins/autotest/testcodeparser.cpp @@ -60,8 +60,10 @@ void TestCodeParser::updateTestTree() m_model->removeAllAutoTests(); m_model->removeAllQuickTests(); const ProjectExplorer::SessionManager *session = ProjectExplorer::SessionManager::instance(); - if (!session || !session->hasProjects()) + if (!session || !session->hasProjects()) { + m_currentProject = 0; return; + } m_currentProject = session->startupProject(); if (!m_currentProject) @@ -285,13 +287,13 @@ void TestCodeParser::checkDocumentForTestCode(CPlusPlus::Document::Ptr doc) } TestVisitor myVisitor(tc); myVisitor.accept(declaringDoc->globalNamespace()); - const QMap<QString, TestCodeLocation> privSlots = myVisitor.privateSlots(); + const QMap<QString, TestCodeLocationAndType> privSlots = myVisitor.privateSlots(); foreach (const QString &privS, privSlots.keys()) { - const TestCodeLocation location = privSlots.value(privS); - TestTreeItem *ttSub = new TestTreeItem(privS, location.m_fileName, - TestTreeItem::TEST_FUNCTION, ttItem); - ttSub->setLine(location.m_line); - ttSub->setColumn(location.m_column); + const TestCodeLocationAndType locationAndType = privSlots.value(privS); + TestTreeItem *ttSub = new TestTreeItem(privS, locationAndType.m_fileName, + locationAndType.m_type, ttItem); + ttSub->setLine(locationAndType.m_line); + ttSub->setColumn(locationAndType.m_column); ttItem->appendChild(ttSub); } @@ -374,8 +376,8 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc) QmlJS::AST::Node::accept(ast, &qmlVisitor); const QString tcName = qmlVisitor.testCaseName(); - const TestCodeLocation tcLocation = qmlVisitor.testCaseLocation(); - const QMap<QString, TestCodeLocation> testFunctions = qmlVisitor.testFunctions(); + const TestCodeLocationAndType tcLocationAndType = qmlVisitor.testCaseLocation(); + const QMap<QString, TestCodeLocationAndType> testFunctions = qmlVisitor.testFunctions(); const QModelIndex quickTestRootIndex = m_model->index(1, 0); TestTreeItem *quickTestRootItem = static_cast<TestTreeItem *>(quickTestRootIndex.internalPointer()); @@ -417,11 +419,11 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc) } foreach (const QString &func, testFunctions.keys()) { - const TestCodeLocation location = testFunctions.value(func); - TestTreeItem *ttSub = new TestTreeItem(func, location.m_fileName, - TestTreeItem::TEST_FUNCTION, ttItem); - ttSub->setLine(location.m_line); - ttSub->setColumn(location.m_column); + const TestCodeLocationAndType locationAndType = testFunctions.value(func); + TestTreeItem *ttSub = new TestTreeItem(func, locationAndType.m_fileName, + locationAndType.m_type, ttItem); + ttSub->setLine(locationAndType.m_line); + ttSub->setColumn(locationAndType.m_column); ttSub->setMainFile(doc->fileName()); ttItem->appendChild(ttSub); } @@ -445,23 +447,23 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc) } // end of handling test cases without name property // construct new/modified TestTreeItem - TestTreeItem *ttItem = new TestTreeItem(tcName, tcLocation.m_fileName, - TestTreeItem::TEST_CLASS, quickTestRootItem); - ttItem->setLine(tcLocation.m_line); - ttItem->setColumn(tcLocation.m_column); + TestTreeItem *ttItem = new TestTreeItem(tcName, tcLocationAndType.m_fileName, + tcLocationAndType.m_type, quickTestRootItem); + ttItem->setLine(tcLocationAndType.m_line); + ttItem->setColumn(tcLocationAndType.m_column); ttItem->setMainFile(doc->fileName()); foreach (const QString &func, testFunctions.keys()) { - const TestCodeLocation location = testFunctions.value(func); - TestTreeItem *ttSub = new TestTreeItem(func, location.m_fileName, - TestTreeItem::TEST_FUNCTION, ttItem); - ttSub->setLine(location.m_line); - ttSub->setColumn(location.m_column); + const TestCodeLocationAndType locationAndType = testFunctions.value(func); + TestTreeItem *ttSub = new TestTreeItem(func, locationAndType.m_fileName, + locationAndType.m_type, ttItem); + ttSub->setLine(locationAndType.m_line); + ttSub->setColumn(locationAndType.m_column); ttItem->appendChild(ttSub); } // update model and internal map - const QString fileName(tcLocation.m_fileName); + const QString fileName(tcLocationAndType.m_fileName); const QmlJS::Document::Ptr qmlDoc = QmlJSTools::Internal::ModelManager::instance()->snapshot().document(fileName); @@ -497,7 +499,7 @@ void TestCodeParser::handleQtQuickTest(CPlusPlus::Document::Ptr doc) m_model->addQuickTest(ttItem); TestInfo ti(tcName, testFunctions.keys(), 0, qmlDoc->editorRevision()); ti.setReferencingFile(doc->fileName()); - m_quickDocMap.insert(tcLocation.m_fileName, ti); + m_quickDocMap.insert(tcLocationAndType.m_fileName, ti); } } } diff --git a/plugins/autotest/testconfiguration.cpp b/plugins/autotest/testconfiguration.cpp index bcb90d75b5..73cdbdb918 100644 --- a/plugins/autotest/testconfiguration.cpp +++ b/plugins/autotest/testconfiguration.cpp @@ -81,6 +81,11 @@ void TestConfiguration::setWorkingDirectory(const QString &workingDirectory) m_workingDir = workingDirectory; } +void TestConfiguration::setDisplayName(const QString &displayName) +{ + m_displayName = displayName; +} + void TestConfiguration::setEnvironment(const Utils::Environment &env) { m_environment = env; diff --git a/plugins/autotest/testconfiguration.h b/plugins/autotest/testconfiguration.h index aa82b8e2b5..54be3697aa 100644 --- a/plugins/autotest/testconfiguration.h +++ b/plugins/autotest/testconfiguration.h @@ -46,6 +46,7 @@ public: void setTargetName(const QString &targetName); void setProFile(const QString &proFile); void setWorkingDirectory(const QString &workingDirectory); + void setDisplayName(const QString &displayName); void setEnvironment(const Utils::Environment &env); void setProject(ProjectExplorer::Project *project); @@ -56,6 +57,7 @@ public: QString targetFile() const { return m_targetFile; } QString targetName() const { return m_targetName; } QString workingDirectory() const { return m_workingDir; } + QString displayName() const { return m_displayName; } Utils::Environment environment() const { return m_environment; } ProjectExplorer::Project *project() const { return m_project; } @@ -72,6 +74,7 @@ private: QString m_targetFile; QString m_targetName; QString m_workingDir; + QString m_displayName; Utils::Environment m_environment; ProjectExplorer::Project *m_project; }; diff --git a/plugins/autotest/testresultspane.cpp b/plugins/autotest/testresultspane.cpp index e9d0f1be56..39441d9087 100644 --- a/plugins/autotest/testresultspane.cpp +++ b/plugins/autotest/testresultspane.cpp @@ -50,9 +50,9 @@ TestResultsPane::TestResultsPane(QObject *parent) : QPalette pal; pal.setColor(QPalette::Window, - Utils::creatorTheme()->color(Utils::Theme::SearchResultWidgetBackgroundColor)); + Utils::creatorTheme()->color(Utils::Theme::InfoBarBackground)); pal.setColor(QPalette::WindowText, - Utils::creatorTheme()->color(Utils::Theme::SearchResultWidgetTextColor)); + Utils::creatorTheme()->color(Utils::Theme::InfoBarText)); m_summaryWidget = new QFrame; m_summaryWidget->setPalette(pal); m_summaryWidget->setAutoFillBackground(true); diff --git a/plugins/autotest/testrunner.cpp b/plugins/autotest/testrunner.cpp index ed2383bb3f..420360468b 100644 --- a/plugins/autotest/testrunner.cpp +++ b/plugins/autotest/testrunner.cpp @@ -351,8 +351,14 @@ void TestRunner::runTests() } ProjectExplorer::Project *project = m_selectedTests.at(0)->project(); - if (!project) // add a warning or info to output? possible at all? + if (!project) { + TestResultsPane::instance()->addTestResult( + TestResult(QString(), QString(), QString(), ResultType::MESSAGE_WARN, + tr("*** Project is null - canceling Test Run ***\n" + "Actually only Desktop kits are supported - make sure the " + "current active kit is a Desktop kit."))); return; + } ProjectExplorer::ProjectExplorerPlugin *pep = ProjectExplorer::ProjectExplorerPlugin::instance(); ProjectExplorer::Internal::ProjectExplorerSettings pes = pep->projectExplorerSettings(); diff --git a/plugins/autotest/testtreeitem.cpp b/plugins/autotest/testtreeitem.cpp index 5ffd192761..2da060da52 100644 --- a/plugins/autotest/testtreeitem.cpp +++ b/plugins/autotest/testtreeitem.cpp @@ -24,11 +24,29 @@ namespace Internal { TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type type, TestTreeItem *parent) : m_name(name), m_filePath(filePath), - m_checked(type == ROOT ? Qt::Unchecked : Qt::Checked), m_type(type), m_line(0), m_parent(parent) { + switch (m_type) { + case ROOT: + m_checked = Qt::Unchecked; + break; + case TEST_CLASS: + case TEST_FUNCTION: + m_checked = Qt::Checked; + break; + case TEST_DATAFUNCTION: + case TEST_SPECIALFUNCTION: + if (m_parent) + m_checked = m_parent->checked() == Qt::PartiallyChecked ? Qt::Unchecked + : m_parent->checked(); + else + m_checked = Qt::Unchecked; + break; + default: + m_checked = Qt::Unchecked; + } } TestTreeItem::~TestTreeItem() @@ -121,19 +139,37 @@ bool TestTreeItem::modifyContent(const TestTreeItem *modified) void TestTreeItem::setChecked(const Qt::CheckState checkState) { switch (m_type) { - case ROOT: - return; - case TEST_FUNCTION: + case TEST_FUNCTION: { m_checked = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked); m_parent->revalidateCheckState(); break; - case TEST_CLASS: + } + case TEST_CLASS: { Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked); foreach (TestTreeItem *child, m_children) { child->setChecked(usedState); } m_checked = usedState; } + default: + return; + } +} + +Qt::CheckState TestTreeItem::checked() const +{ + switch (m_type) { + case TEST_CLASS: + case TEST_FUNCTION: + return m_checked; + case TEST_DATAFUNCTION: + case TEST_SPECIALFUNCTION: + return m_parent->m_checked == Qt::PartiallyChecked ? Qt::Unchecked : m_parent->m_checked; + default: + if (m_parent) + return m_parent->m_checked; + } + return Qt::Unchecked; } void TestTreeItem::revalidateCheckState() @@ -143,8 +179,16 @@ void TestTreeItem::revalidateCheckState() bool foundChecked = false; bool foundUnchecked = false; foreach (const TestTreeItem *child, m_children) { - foundChecked |= (child->m_checked != Qt::Unchecked); - foundUnchecked |= (child->m_checked == Qt::Unchecked); + switch (child->type()) { + case TEST_DATAFUNCTION: + case TEST_SPECIALFUNCTION: + continue; + default: + break; + } + + foundChecked |= (child->checked() != Qt::Unchecked); + foundUnchecked |= (child->checked() == Qt::Unchecked); if (foundChecked && foundUnchecked) { m_checked = Qt::PartiallyChecked; return; diff --git a/plugins/autotest/testtreeitem.h b/plugins/autotest/testtreeitem.h index 6f0ca88e2d..8ec916b0bf 100644 --- a/plugins/autotest/testtreeitem.h +++ b/plugins/autotest/testtreeitem.h @@ -30,7 +30,11 @@ class TestTreeItem public: enum Type { - ROOT, TEST_CLASS, TEST_FUNCTION + ROOT, + TEST_CLASS, + TEST_FUNCTION, + TEST_DATAFUNCTION, + TEST_SPECIALFUNCTION }; TestTreeItem(const QString &name, const QString &filePath, Type type, TestTreeItem *parent = 0); @@ -57,7 +61,7 @@ public: QString mainFile() const { return m_mainFile; } void setMainFile(const QString &mainFile) { m_mainFile = mainFile; } void setChecked(const Qt::CheckState checked); - Qt::CheckState checked() const { return m_checked; } + Qt::CheckState checked() const; Type type() const { return m_type; } void setParent(TestTreeItem *parent) { m_parent = parent; } diff --git a/plugins/autotest/testtreeitemdelegate.cpp b/plugins/autotest/testtreeitemdelegate.cpp new file mode 100644 index 0000000000..71ccef5756 --- /dev/null +++ b/plugins/autotest/testtreeitemdelegate.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "testtreeitemdelegate.h" +#include "testtreemodel.h" + +#include <QPainter> + +namespace Autotest { +namespace Internal { + +TestTreeItemDelegate::TestTreeItemDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ +} + +TestTreeItemDelegate::~TestTreeItemDelegate() +{ +} + +void TestTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QStyleOptionViewItem opt = option; + initStyleOption(&opt, index); + + bool italic = index.data(ItalicRole).toBool(); + if (italic) { + QFont font(option.font); + font.setItalic(true); + opt.font = font; + + // correct margin of items without a checkbox (except for root items) + QStyleOptionButton styleOpt; + styleOpt.initFrom(opt.widget); + const QSize sz; // no text, no icon - we just need the size of the check box + QSize cbSize = opt.widget->style()->sizeFromContents(QStyle::CT_CheckBox, &styleOpt, sz); + // the 6 results from hard coded margins of the checkbox itself (2x2) and the item (1x2) + opt.rect.setLeft(opt.rect.left() + cbSize.width() + 6); + + // HACK make sure the pixels that have been moved right are painted for selections + if (opt.state & QStyle::State_Selected) { + QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled + ? QPalette::Normal : QPalette::Disabled; + if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active)) + cg = QPalette::Inactive; + painter->fillRect(option.rect, opt.palette.brush(cg, QPalette::Highlight)); + } + } + + QStyledItemDelegate::paint(painter, opt, index); +} + +} // namespace Internal +} // namespace Autotest diff --git a/plugins/autotest/testtreeitemdelegate.h b/plugins/autotest/testtreeitemdelegate.h new file mode 100644 index 0000000000..af31022b0b --- /dev/null +++ b/plugins/autotest/testtreeitemdelegate.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef TESTTREEITEMDELEGATE_H +#define TESTTREEITEMDELEGATE_H + +#include <QStyledItemDelegate> + +namespace Autotest { +namespace Internal { + +class TestTreeItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + TestTreeItemDelegate(QObject *parent = 0); + ~TestTreeItemDelegate(); + +public: + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; +}; + +} // namespace Internal +} // namespace Autotest + +#endif // TESTTREEITEMDELEGATE_H diff --git a/plugins/autotest/testtreemodel.cpp b/plugins/autotest/testtreemodel.cpp index 93d9d160ef..8425c27c1d 100644 --- a/plugins/autotest/testtreemodel.cpp +++ b/plugins/autotest/testtreemodel.cpp @@ -135,6 +135,8 @@ static QIcon testTreeIcon(TestTreeItem::Type type) QIcon(QLatin1String(":/images/class.png")), QIcon(QLatin1String(":/images/func.png")) }; + if (type >= 3) + return icons[2]; return icons[type]; } @@ -169,15 +171,46 @@ QVariant TestTreeModel::data(const QModelIndex &index, int role) const case Qt::DecorationRole: return testTreeIcon(item->type()); case Qt::CheckStateRole: - if (item->type() == TestTreeItem::ROOT) + switch (item->type()) { + case TestTreeItem::ROOT: + case TestTreeItem::TEST_DATAFUNCTION: + case TestTreeItem::TEST_SPECIALFUNCTION: return QVariant(); - return item->checked(); - case LinkRole: + case TestTreeItem::TEST_CLASS: + if (item->name().isEmpty()) + return QVariant(); + else + return item->checked(); + case TestTreeItem::TEST_FUNCTION: + if (TestTreeItem *parent = item->parent()) + return parent->name().isEmpty() ? QVariant() : item->checked(); + else + return item->checked(); + default: + return item->checked(); + } + case LinkRole: { QVariant itemLink; TextEditor::TextEditorWidget::Link link(item->filePath(), item->line(), item->column()); itemLink.setValue(link); return itemLink; } + case ItalicRole: + switch (item->type()) { + case TestTreeItem::TEST_DATAFUNCTION: + case TestTreeItem::TEST_SPECIALFUNCTION: + return true; + case TestTreeItem::TEST_CLASS: + return item->name().isEmpty(); + case TestTreeItem::TEST_FUNCTION: + if (TestTreeItem *parent = item->parent()) + return parent->name().isEmpty(); + else + return false; + default: + return false; + } + } // TODO ? return QVariant(); @@ -222,15 +255,18 @@ Qt::ItemFlags TestTreeModel::flags(const QModelIndex &index) const switch(item->type()) { case TestTreeItem::TEST_CLASS: if (item->name().isEmpty()) - return Qt::ItemIsSelectable | Qt::ItemIsTristate; + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsTristate | Qt::ItemIsUserCheckable; case TestTreeItem::TEST_FUNCTION: if (item->parent()->name().isEmpty()) - return Qt::ItemIsSelectable; + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; case TestTreeItem::ROOT: - default: return Qt::ItemIsEnabled; + case TestTreeItem::TEST_DATAFUNCTION: + case TestTreeItem::TEST_SPECIALFUNCTION: + default: + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } } @@ -261,18 +297,38 @@ bool TestTreeModel::hasTests() const static void addProjectInformation(TestConfiguration *config, const QString &filePath) { + const ProjectExplorer::SessionManager *session = ProjectExplorer::SessionManager::instance(); + if (!session || !session->hasProjects()) + return; + + ProjectExplorer::Project *project = session->startupProject(); + if (!project) + return; + QString targetFile; QString targetName; QString workDir; QString proFile; + QString displayName; Utils::Environment env; - ProjectExplorer::Project *project = 0; + bool hasDesktopTarget = false; CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); - QList<CppTools::ProjectPart::Ptr> projParts = cppMM->projectPart(filePath); + QList<CppTools::ProjectPart::Ptr> projParts = cppMM->projectInfo(project).projectParts(); + if (!projParts.empty()) { - proFile = projParts.at(0)->projectFile; - project = projParts.at(0)->project; // necessary to grab this here? or should this be the current active startup project anyway? + foreach (const CppTools::ProjectPart::Ptr &part, projParts) { + foreach (const CppTools::ProjectFile currentFile, part->files) { + if (currentFile.path == filePath) { + proFile = part->projectFile; + displayName = part->displayName; + break; + } + } + if (!proFile.isEmpty()) // maybe better use a goto instead of the break above?? + break; + } } + if (project) { if (auto target = project->activeTarget()) { ProjectExplorer::BuildTargetInfoList appTargets = target->applicationTargets(); @@ -289,6 +345,7 @@ static void addProjectInformation(TestConfiguration *config, const QString &file if (ProjectExplorer::LocalApplicationRunConfiguration *localRunConfiguration = qobject_cast<ProjectExplorer::LocalApplicationRunConfiguration *>(rc)) { if (localRunConfiguration->executable() == targetFile) { + hasDesktopTarget = true; workDir = Utils::FileUtils::normalizePathName( localRunConfiguration->workingDirectory()); ProjectExplorer::EnvironmentAspect *envAsp @@ -300,12 +357,19 @@ static void addProjectInformation(TestConfiguration *config, const QString &file } } } - config->setTargetFile(targetFile); - config->setTargetName(targetName); - config->setWorkingDirectory(workDir); - config->setProFile(proFile); - config->setEnvironment(env); - config->setProject(project); + + if (hasDesktopTarget) { + config->setTargetFile(targetFile); + config->setTargetName(targetName); + config->setWorkingDirectory(workDir); + config->setProFile(proFile); + config->setEnvironment(env); + config->setProject(project); + config->setDisplayName(displayName); + } else { + config->setProFile(proFile); + config->setDisplayName(displayName); + } } QList<TestConfiguration *> TestTreeModel::getAllTestCases() const @@ -392,17 +456,18 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const QMap<QString, TestConfiguration *> foundMains; - TestTreeItem *unnamed = unnamedQuickTests(); - for (int childRow = 0, ccount = unnamed->childCount(); childRow < ccount; ++ childRow) { - const TestTreeItem *grandChild = unnamed->child(childRow); - const QString mainFile = grandChild->mainFile(); - if (foundMains.contains(mainFile)) { - foundMains[mainFile]->setTestCaseCount(tc->testCaseCount() + 1); - } else { - TestConfiguration *tc = new TestConfiguration(QString(), QStringList()); - tc->setTestCaseCount(1); - addProjectInformation(tc, mainFile); - foundMains.insert(mainFile, tc); + if (TestTreeItem *unnamed = unnamedQuickTests()) { + for (int childRow = 0, ccount = unnamed->childCount(); childRow < ccount; ++ childRow) { + const TestTreeItem *grandChild = unnamed->child(childRow); + const QString mainFile = grandChild->mainFile(); + if (foundMains.contains(mainFile)) { + foundMains[mainFile]->setTestCaseCount(tc->testCaseCount() + 1); + } else { + TestConfiguration *tc = new TestConfiguration(QString(), QStringList()); + tc->setTestCaseCount(1); + addProjectInformation(tc, mainFile); + foundMains.insert(mainFile, tc); + } } } @@ -695,6 +760,8 @@ bool TestTreeSortFilterModel::lessThan(const QModelIndex &left, const QModelInde switch (m_sortMode) { case Alphabetically: + if (leftVal == rightVal) + return left.row() > right.row(); return leftVal > rightVal; case Naturally: { const TextEditor::TextEditorWidget::Link leftLink = @@ -717,13 +784,20 @@ bool TestTreeSortFilterModel::lessThan(const QModelIndex &left, const QModelInde bool TestTreeSortFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { - // TODO add filtering capabilities QModelIndex index = m_sourceModel->index(sourceRow, 0,sourceParent); if (!index.isValid()) return false; + const TestTreeItem *item = static_cast<TestTreeItem *>(index.internalPointer()); - return true; + switch (item->type()) { + case TestTreeItem::TEST_DATAFUNCTION: + return m_filterMode & ShowTestData; + case TestTreeItem::TEST_SPECIALFUNCTION: + return m_filterMode & ShowInitAndCleanup; + default: + return true; + } } } // namespace Internal diff --git a/plugins/autotest/testtreemodel.h b/plugins/autotest/testtreemodel.h index 94cb874f8e..5ae83f0df7 100644 --- a/plugins/autotest/testtreemodel.h +++ b/plugins/autotest/testtreemodel.h @@ -29,7 +29,8 @@ namespace { enum ItemRole { // AnnotationRole = Qt::UserRole + 1, - LinkRole = Qt::UserRole + 2 // can be removed if AnnotationRole comes back + LinkRole = Qt::UserRole + 2, // can be removed if AnnotationRole comes back + ItalicRole // used only inside the delegate }; } diff --git a/plugins/autotest/testtreeview.cpp b/plugins/autotest/testtreeview.cpp index 45376db383..fdd3ee4096 100644 --- a/plugins/autotest/testtreeview.cpp +++ b/plugins/autotest/testtreeview.cpp @@ -20,6 +20,7 @@ #include "testcodeparser.h" #include "testrunner.h" #include "testtreeitem.h" +#include "testtreeitemdelegate.h" #include "testtreemodel.h" #include "testtreeview.h" @@ -53,6 +54,7 @@ TestTreeViewWidget::TestTreeViewWidget(QWidget *parent) : m_view = new TestTreeView(this); m_view->setModel(m_sortFilterModel); m_view->setSortingEnabled(true); + m_view->setItemDelegate(new TestTreeItemDelegate(this)); QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); diff --git a/plugins/autotest/testvisitor.cpp b/plugins/autotest/testvisitor.cpp index 199f3236b2..b6706b5bf4 100644 --- a/plugins/autotest/testvisitor.cpp +++ b/plugins/autotest/testvisitor.cpp @@ -44,7 +44,7 @@ TestVisitor::~TestVisitor() { } -static QList<QString> ignoredFunctions = QList<QString>() << QLatin1String("initTestCase") +static QList<QString> specialFunctions = QList<QString>() << QLatin1String("initTestCase") << QLatin1String("cleanupTestCase") << QLatin1String("init") << QLatin1String("cleanup"); @@ -66,14 +66,18 @@ bool TestVisitor::visit(CPlusPlus::Class *symbol) if (const auto func = type->asFunctionType()) { if (func->isSlot() && member->isPrivate()) { const QString name = o.prettyName(func->name()); - if (!ignoredFunctions.contains(name) && !name.endsWith(QLatin1String("_data"))) { - // TODO use definition of function instead of declaration! - TestCodeLocation location; - location.m_fileName = QLatin1String(member->fileName()); - location.m_line = member->line(); - location.m_column = member->column() - 1; - m_privSlots.insert(name, location); - } + // TODO use definition of function instead of declaration! + TestCodeLocationAndType locationAndType; + locationAndType.m_fileName = QLatin1String(member->fileName()); + locationAndType.m_line = member->line(); + locationAndType.m_column = member->column() - 1; + if (specialFunctions.contains(name)) + locationAndType.m_type = TestTreeItem::TEST_SPECIALFUNCTION; + else if (name.endsWith(QLatin1String("_data"))) + locationAndType.m_type = TestTreeItem::TEST_DATAFUNCTION; + else + locationAndType.m_type = TestTreeItem::TEST_FUNCTION; + m_privSlots.insert(name, locationAndType); } } } @@ -146,13 +150,14 @@ bool TestQmlVisitor::visit(QmlJS::AST::UiObjectDefinition *ast) { const QStringRef name = ast->qualifiedTypeNameId->name; if (name != QLatin1String("TestCase")) - return false; + return true; // find nested TestCase items as well m_currentTestCaseName.clear(); const auto sourceLocation = ast->firstSourceLocation(); m_testCaseLocation.m_fileName = m_currentDoc->fileName(); m_testCaseLocation.m_line = sourceLocation.startLine; m_testCaseLocation.m_column = sourceLocation.startColumn - 1; + m_testCaseLocation.m_type = TestTreeItem::TEST_CLASS; return true; } @@ -173,12 +178,13 @@ bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast) const QStringRef name = ast->name; if (name.startsWith(QLatin1String("test_"))) { const auto sourceLocation = ast->firstSourceLocation(); - TestCodeLocation location; - location.m_fileName = m_currentDoc->fileName(); - location.m_line = sourceLocation.startLine; - location.m_column = sourceLocation.startColumn - 1; + TestCodeLocationAndType locationAndType; + locationAndType.m_fileName = m_currentDoc->fileName(); + locationAndType.m_line = sourceLocation.startLine; + locationAndType.m_column = sourceLocation.startColumn - 1; + locationAndType.m_type = TestTreeItem::TEST_FUNCTION; - m_testFunctions.insert(name.toString(), location); + m_testFunctions.insert(name.toString(), locationAndType); } return false; } diff --git a/plugins/autotest/testvisitor.h b/plugins/autotest/testvisitor.h index 92bfa009ae..bba9f0ebda 100644 --- a/plugins/autotest/testvisitor.h +++ b/plugins/autotest/testvisitor.h @@ -19,6 +19,8 @@ #ifndef TESTVISITOR_H #define TESTVISITOR_H +#include "testtreeitem.h" + #include <cplusplus/ASTVisitor.h> #include <cplusplus/CppDocument.h> #include <cplusplus/Scope.h> @@ -33,10 +35,11 @@ namespace Autotest { namespace Internal { -struct TestCodeLocation { +struct TestCodeLocationAndType { QString m_fileName; unsigned m_line; unsigned m_column; + TestTreeItem::Type m_type; }; class TestVisitor : public CPlusPlus::SymbolVisitor @@ -45,13 +48,13 @@ public: TestVisitor(const QString &fullQualifiedClassName); virtual ~TestVisitor(); - QMap<QString, TestCodeLocation> privateSlots() const { return m_privSlots; } + QMap<QString, TestCodeLocationAndType> privateSlots() const { return m_privSlots; } bool visit(CPlusPlus::Class *symbol); private: QString m_className; - QMap<QString, TestCodeLocation> m_privSlots; + QMap<QString, TestCodeLocationAndType> m_privSlots; }; class TestAstVisitor : public CPlusPlus::ASTVisitor @@ -85,14 +88,14 @@ public: bool visit(QmlJS::AST::StringLiteral *ast); QString testCaseName() const { return m_currentTestCaseName; } - TestCodeLocation testCaseLocation() const { return m_testCaseLocation; } - QMap<QString, TestCodeLocation> testFunctions() const { return m_testFunctions; } + TestCodeLocationAndType testCaseLocation() const { return m_testCaseLocation; } + QMap<QString, TestCodeLocationAndType> testFunctions() const { return m_testFunctions; } private: QmlJS::Document::Ptr m_currentDoc; QString m_currentTestCaseName; - TestCodeLocation m_testCaseLocation; - QMap<QString, TestCodeLocation> m_testFunctions; + TestCodeLocationAndType m_testCaseLocation; + QMap<QString, TestCodeLocationAndType> m_testFunctions; }; |