/**************************************************************************** ** ** 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 "gtesttreeitem.h" #include "gtestconfiguration.h" #include "gtestparser.h" #include "../autotest_utils.h" #include #include namespace Autotest { namespace Internal { static QString gtestFilter(GTestTreeItem::TestStates states) { if ((states & GTestTreeItem::Parameterized) && (states & GTestTreeItem::Typed)) return QLatin1String("*/%1/*.%2"); if (states & GTestTreeItem::Parameterized) return QLatin1String("*/%1.%2/*"); if (states & GTestTreeItem::Typed) return QLatin1String("%1/*.%2"); return QLatin1String("%1.%2"); } GTestTreeItem *GTestTreeItem::createTestItem(const TestParseResult *result) { const GTestParseResult *parseResult = static_cast(result); GTestTreeItem *item = new GTestTreeItem(parseResult->name, parseResult->fileName, parseResult->itemType); item->setProFile(parseResult->proFile); item->setLine(parseResult->line); item->setColumn(parseResult->column); if (parseResult->parameterized) item->setState(Parameterized); if (parseResult->typed) item->setState(Typed); if (parseResult->disabled) item->setState(Disabled); foreach (const TestParseResult *testSet, parseResult->children) item->appendChild(createTestItem(testSet)); return item; } QVariant GTestTreeItem::data(int column, int role) const { switch (role) { case Qt::DisplayRole: { if (type() == TestTreeItem::Root) break; const QString &displayName = (m_state & Disabled) ? name().mid(9) : name(); return QVariant(displayName + nameSuffix()); } case Qt::CheckStateRole: switch (type()) { case TestCase: case TestFunctionOrSet: return checked(); default: return QVariant(); } case ItalicRole: return false; case EnabledRole: return !(m_state & Disabled); default: break; } return TestTreeItem::data(column, role); } TestConfiguration *GTestTreeItem::testConfiguration() const { ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); QTC_ASSERT(project, return 0); GTestConfiguration *config = 0; switch (type()) { case TestCase: { const QString &testSpecifier = gtestFilter(state()).arg(name()).arg(QLatin1Char('*')); if (int count = childCount()) { config = new GTestConfiguration; config->setTestCases(QStringList(testSpecifier)); config->setTestCaseCount(count); config->setProFile(proFile()); config->setProject(project); // item has no filePath set - so take it of the first children config->setDisplayName( TestUtils::getCMakeDisplayNameIfNecessary(childItem(0)->filePath(), proFile())); } break; } case TestFunctionOrSet: { GTestTreeItem *parent = static_cast(parentItem()); if (!parent) return 0; const QString &testSpecifier = gtestFilter(parent->state()).arg(parent->name()).arg(name()); config = new GTestConfiguration; config->setTestCases(QStringList(testSpecifier)); config->setProFile(proFile()); config->setProject(project); config->setDisplayName( TestUtils::getCMakeDisplayNameIfNecessary(filePath(), parent->proFile())); break; } default: return 0; } return config; } // used as key inside getAllTestCases()/getSelectedTestCases() for Google Tests class ProFileWithDisplayName { public: ProFileWithDisplayName(const QString &file, const QString &name) : proFile(file), displayName(name) {} QString proFile; QString displayName; bool operator==(const ProFileWithDisplayName &rhs) const { return proFile == rhs.proFile && displayName == rhs.displayName; } }; // needed as ProFileWithDisplayName is used as key inside a QHash bool operator<(const ProFileWithDisplayName &lhs, const ProFileWithDisplayName &rhs) { return lhs.proFile == rhs.proFile ? lhs.displayName < rhs.displayName : lhs.proFile < rhs.proFile; } // needed as ProFileWithDisplayName is used as a key inside a QHash uint qHash(const ProFileWithDisplayName &lhs) { return ::qHash(lhs.proFile) ^ ::qHash(lhs.displayName); } QList GTestTreeItem::getAllTestConfigurations() const { QList result; ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project || type() != Root) return result; QHash proFilesWithTestSets; for (int row = 0, count = childCount(); row < count; ++row) { const GTestTreeItem *child = static_cast(childItem(row)); const int grandChildCount = child->childCount(); for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) { const TestTreeItem *grandChild = child->childItem(grandChildRow); ProFileWithDisplayName key(grandChild->proFile(), TestUtils::getCMakeDisplayNameIfNecessary(grandChild->filePath(), grandChild->proFile())); proFilesWithTestSets.insert(key, proFilesWithTestSets[key] + 1); } } QHash::ConstIterator it = proFilesWithTestSets.begin(); QHash::ConstIterator end = proFilesWithTestSets.end(); for ( ; it != end; ++it) { const ProFileWithDisplayName &key = it.key(); GTestConfiguration *tc = new GTestConfiguration; tc->setTestCaseCount(it.value()); tc->setProFile(key.proFile); tc->setDisplayName(key.displayName); tc->setProject(project); result << tc; } return result; } struct TestCases { QStringList filters; int additionalTestCaseCount = 0; }; static const ProFileWithDisplayName createProfile(const TestTreeItem *item) { return ProFileWithDisplayName( item->proFile(), TestUtils::getCMakeDisplayNameIfNecessary(item->filePath(), item->proFile())); } QList GTestTreeItem::getSelectedTestConfigurations() const { QList result; ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project || type() != Root) return result; QHash proFilesWithCheckedTestSets; for (int row = 0, count = childCount(); row < count; ++row) { const GTestTreeItem *child = static_cast(childItem(row)); const int grandChildCount = child->childCount(); QTC_ASSERT(grandChildCount != 0, continue); switch (child->checked()) { case Qt::Unchecked: continue; case Qt::Checked: { auto &testCases = proFilesWithCheckedTestSets[createProfile(child->childItem(0))]; testCases.filters.append(gtestFilter(child->state()).arg(child->name()).arg('*')); testCases.additionalTestCaseCount += grandChildCount - 1; break; } case Qt::PartiallyChecked: { for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) { const TestTreeItem *grandChild = child->childItem(grandChildRow); if (grandChild->checked() == Qt::Checked) { proFilesWithCheckedTestSets[createProfile(grandChild)].filters.append( gtestFilter(child->state()).arg(child->name()).arg(grandChild->name())); } } break; } } } QHash::ConstIterator it = proFilesWithCheckedTestSets.begin(); QHash::ConstIterator end = proFilesWithCheckedTestSets.end(); for ( ; it != end; ++it) { const ProFileWithDisplayName &proFileWithDisplayName = it.key(); GTestConfiguration *tc = new GTestConfiguration; tc->setTestCases(it.value().filters); tc->setTestCaseCount(tc->testCaseCount() + it.value().additionalTestCaseCount); tc->setProFile(proFileWithDisplayName.proFile); tc->setDisplayName(proFileWithDisplayName.displayName); tc->setProject(project); result << tc; } return result; } TestTreeItem *GTestTreeItem::find(const TestParseResult *result) { QTC_ASSERT(result, return 0); const GTestParseResult *parseResult = static_cast(result); GTestTreeItem::TestStates states = parseResult->disabled ? GTestTreeItem::Disabled : GTestTreeItem::Enabled; if (parseResult->parameterized) states |= GTestTreeItem::Parameterized; if (parseResult->typed) states |= GTestTreeItem::Typed; switch (type()) { case Root: return findChildByNameStateAndFile(parseResult->name, states, parseResult->proFile); case TestCase: return findChildByNameAndFile(result->name, result->fileName); default: return 0; } } bool GTestTreeItem::modify(const TestParseResult *result) { QTC_ASSERT(result, return false); switch (type()) { case TestFunctionOrSet: return modifyTestSetContent(static_cast(result)); default: return false; } } bool GTestTreeItem::modifyTestSetContent(const GTestParseResult *result) { bool hasBeenModified = modifyLineAndColumn(result->line, result->column); GTestTreeItem::TestStates states = result->disabled ? GTestTreeItem::Disabled : GTestTreeItem::Enabled; if (m_state != states) { m_state = states; hasBeenModified = true; } return hasBeenModified; } TestTreeItem *GTestTreeItem::findChildByNameStateAndFile(const QString &name, GTestTreeItem::TestStates state, const QString &proFile) const { return findChildBy([name, state, proFile](const TestTreeItem *other) -> bool { const GTestTreeItem *gtestItem = static_cast(other); return other->proFile() == proFile && other->name() == name && gtestItem->state() == state; }); } QString GTestTreeItem::nameSuffix() const { static QString markups[] = { QCoreApplication::translate("GTestTreeItem", "parameterized"), QCoreApplication::translate("GTestTreeItem", "typed") }; QString suffix; if (m_state & Parameterized) suffix = QLatin1String(" [") + markups[0]; if (m_state & Typed) suffix += (suffix.isEmpty() ? QLatin1String(" [") : QLatin1String(", ")) + markups[1]; if (!suffix.isEmpty()) suffix += QLatin1Char(']'); return suffix; } } // namespace Internal } // namespace Autotest