2018-12-07 10:00:23 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2019 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 "boosttesttreeitem.h"
|
|
|
|
|
#include "boosttestconstants.h"
|
|
|
|
|
#include "boosttestconfiguration.h"
|
2020-10-06 15:27:27 +02:00
|
|
|
#include "boosttestframework.h"
|
2018-12-07 10:00:23 +01:00
|
|
|
#include "boosttestparser.h"
|
|
|
|
|
#include "../testframeworkmanager.h"
|
|
|
|
|
|
|
|
|
|
#include <projectexplorer/session.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QRegularExpression>
|
|
|
|
|
|
|
|
|
|
namespace Autotest {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
TestTreeItem *BoostTestTreeItem::copyWithoutChildren()
|
|
|
|
|
{
|
2020-03-26 10:11:39 +01:00
|
|
|
BoostTestTreeItem *copied = new BoostTestTreeItem(framework());
|
2018-12-07 10:00:23 +01:00
|
|
|
copied->copyBasicDataFrom(this);
|
|
|
|
|
copied->m_state = m_state;
|
|
|
|
|
copied->m_fullName = m_fullName;
|
|
|
|
|
return copied;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant BoostTestTreeItem::data(int column, int role) const
|
|
|
|
|
{
|
|
|
|
|
switch (role) {
|
|
|
|
|
case Qt::DisplayRole:
|
|
|
|
|
if (type() == Root)
|
|
|
|
|
break;
|
|
|
|
|
return QString(name() + nameSuffix());
|
|
|
|
|
case Qt::CheckStateRole:
|
|
|
|
|
return checked();
|
|
|
|
|
case ItalicRole:
|
|
|
|
|
return false;
|
|
|
|
|
case EnabledRole:
|
|
|
|
|
return enabled();
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return TestTreeItem::data(column, role);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestTreeItem *BoostTestTreeItem::find(const TestParseResult *result)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(result, return nullptr);
|
|
|
|
|
|
|
|
|
|
const BoostTestParseResult *bResult = static_cast<const BoostTestParseResult *>(result);
|
|
|
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
|
case Root:
|
2020-10-06 15:27:27 +02:00
|
|
|
if (static_cast<BoostTestFramework *>(result->base)->grouping()) {
|
2018-12-07 10:00:23 +01:00
|
|
|
const QFileInfo fileInfo(bResult->fileName);
|
|
|
|
|
const QFileInfo base(fileInfo.absolutePath());
|
|
|
|
|
for (int row = 0; row < childCount(); ++row) {
|
|
|
|
|
BoostTestTreeItem *group = static_cast<BoostTestTreeItem *>(childAt(row));
|
|
|
|
|
if (group->filePath() != base.absoluteFilePath())
|
|
|
|
|
continue;
|
|
|
|
|
if (auto groupChild = group->findChildByNameStateAndFile(
|
|
|
|
|
bResult->name, bResult->state, bResult->proFile)) {
|
|
|
|
|
return groupChild;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return findChildByNameStateAndFile(bResult->name, bResult->state, bResult->proFile);
|
|
|
|
|
case GroupNode:
|
|
|
|
|
case TestSuite:
|
|
|
|
|
return findChildByNameStateAndFile(bResult->name, bResult->state, bResult->proFile);
|
|
|
|
|
default:
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestTreeItem *BoostTestTreeItem::findChild(const TestTreeItem *other)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(other, return nullptr);
|
|
|
|
|
const Type otherType = other->type();
|
|
|
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
|
case Root: {
|
|
|
|
|
TestTreeItem *result = nullptr;
|
|
|
|
|
if (otherType == GroupNode) {
|
|
|
|
|
result = findChildByNameAndFile(other->name(), other->filePath());
|
|
|
|
|
} else if (otherType == TestSuite) {
|
|
|
|
|
auto bOther = static_cast<const BoostTestTreeItem *>(other);
|
|
|
|
|
result = findChildByNameStateAndFile(bOther->name(), bOther->state(),
|
|
|
|
|
bOther->proFile());
|
|
|
|
|
}
|
|
|
|
|
return (result && result->type() == otherType) ? result : nullptr;
|
|
|
|
|
}
|
|
|
|
|
case GroupNode: {
|
|
|
|
|
auto bOther = static_cast<const BoostTestTreeItem *>(other);
|
|
|
|
|
return otherType == TestSuite
|
|
|
|
|
? findChildByNameStateAndFile(bOther->name(), bOther->state(), bOther->proFile())
|
|
|
|
|
: nullptr;
|
|
|
|
|
}
|
|
|
|
|
case TestSuite: {
|
|
|
|
|
if (otherType == TestCase) {
|
|
|
|
|
return findChildByNameAndFile(other->name(), other->filePath());
|
|
|
|
|
} else if (otherType == TestSuite) {
|
|
|
|
|
auto bOther = static_cast<const BoostTestTreeItem *>(other);
|
|
|
|
|
return findChildByNameStateAndFile(other->name(), bOther->state(), other->proFile());
|
|
|
|
|
} else {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BoostTestTreeItem::modify(const TestParseResult *result)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(result, return false);
|
|
|
|
|
return (type() == TestCase || type() == TestSuite)
|
|
|
|
|
? modifyTestContent(static_cast<const BoostTestParseResult *>(result))
|
|
|
|
|
: false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestTreeItem *BoostTestTreeItem::createParentGroupNode() const
|
|
|
|
|
{
|
|
|
|
|
const QFileInfo fileInfo(filePath());
|
|
|
|
|
const QFileInfo base(fileInfo.absolutePath());
|
2020-03-26 10:11:39 +01:00
|
|
|
return new BoostTestTreeItem(framework(), base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
|
2018-12-07 10:00:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString BoostTestTreeItem::prependWithParentsSuitePaths(const QString &testName) const
|
|
|
|
|
{
|
|
|
|
|
QString prepend = type() == TestSuite ? m_fullName.left(m_fullName.lastIndexOf('/'))
|
|
|
|
|
: m_fullName.left(m_fullName.indexOf("::"));
|
|
|
|
|
if (prepend.startsWith(BoostTest::Constants::BOOST_MASTER_SUITE))
|
|
|
|
|
prepend = prepend.mid(QString(BoostTest::Constants::BOOST_MASTER_SUITE).length());
|
|
|
|
|
|
|
|
|
|
return prepend + '/' + testName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QString handleSpecialFunctionNames(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
static const QRegularExpression function(".*\\((.*),.*\\)");
|
|
|
|
|
const QRegularExpressionMatch match = function.match(name);
|
|
|
|
|
if (!match.hasMatch())
|
|
|
|
|
return name;
|
|
|
|
|
QString result = match.captured(1);
|
|
|
|
|
int index = result.lastIndexOf(':');
|
|
|
|
|
if (index != -1)
|
|
|
|
|
result = result.mid(index + 1);
|
|
|
|
|
result.prepend('*').append('*');
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 11:37:37 +02:00
|
|
|
QList<ITestConfiguration *> BoostTestTreeItem::getAllTestConfigurations() const
|
2018-12-07 10:00:23 +01:00
|
|
|
{
|
2020-10-13 11:37:37 +02:00
|
|
|
QList<ITestConfiguration *> result;
|
2018-12-07 10:00:23 +01:00
|
|
|
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
|
|
|
|
|
if (!project || type() != Root)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
struct BoostTestCases {
|
|
|
|
|
int testCases;
|
|
|
|
|
QSet<QString> internalTargets;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// we only need the unique project files (and number of test cases for the progress indicator)
|
|
|
|
|
QHash<QString, BoostTestCases> testsPerProjectfile;
|
|
|
|
|
forAllChildren([&testsPerProjectfile](TreeItem *it){
|
|
|
|
|
auto item = static_cast<BoostTestTreeItem *>(it);
|
|
|
|
|
if (item->type() != TestSuite)
|
|
|
|
|
return;
|
|
|
|
|
int funcChildren = 0;
|
|
|
|
|
item->forAllChildren([&funcChildren](TreeItem *child){
|
|
|
|
|
if (static_cast<BoostTestTreeItem *>(child)->type() == TestCase)
|
|
|
|
|
++funcChildren;
|
|
|
|
|
});
|
|
|
|
|
if (funcChildren) {
|
|
|
|
|
testsPerProjectfile[item->proFile()].testCases += funcChildren;
|
|
|
|
|
testsPerProjectfile[item->proFile()].internalTargets.unite(item->internalTargets());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (auto it = testsPerProjectfile.begin(), end = testsPerProjectfile.end(); it != end; ++it) {
|
2019-10-22 08:38:28 +02:00
|
|
|
for (const QString &target : qAsConst(it.value().internalTargets)) {
|
2020-03-26 10:11:39 +01:00
|
|
|
BoostTestConfiguration *config = new BoostTestConfiguration(framework());
|
2019-10-22 08:38:28 +02:00
|
|
|
config->setProject(project);
|
|
|
|
|
config->setProjectFile(it.key());
|
|
|
|
|
config->setTestCaseCount(it.value().testCases);
|
|
|
|
|
config->setInternalTarget(target);
|
|
|
|
|
result.append(config);
|
|
|
|
|
}
|
2018-12-07 10:00:23 +01:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 11:37:37 +02:00
|
|
|
QList<ITestConfiguration *> BoostTestTreeItem::getTestConfigurations(
|
2020-09-11 14:30:15 +02:00
|
|
|
std::function<bool(BoostTestTreeItem *)> predicate) const
|
2018-12-07 10:00:23 +01:00
|
|
|
{
|
2020-10-13 11:37:37 +02:00
|
|
|
QList<ITestConfiguration *> result;
|
2018-12-07 10:00:23 +01:00
|
|
|
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
|
|
|
|
|
if (!project || type() != Root)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
struct BoostTestCases {
|
|
|
|
|
QStringList testCases;
|
|
|
|
|
QSet<QString> internalTargets;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QHash<QString, BoostTestCases> testCasesForProjectFile;
|
2020-09-11 14:30:15 +02:00
|
|
|
forAllChildren([&testCasesForProjectFile, &predicate](TreeItem *it){
|
2018-12-07 10:00:23 +01:00
|
|
|
auto item = static_cast<BoostTestTreeItem *>(it);
|
|
|
|
|
if (item->type() != TestCase)
|
|
|
|
|
return;
|
|
|
|
|
if (!item->enabled()) // ignore child tests known to be disabled when using run selected
|
|
|
|
|
return;
|
2020-09-11 14:30:15 +02:00
|
|
|
if (predicate(item)) {
|
2019-06-03 14:47:54 +02:00
|
|
|
QString tcName = item->name();
|
|
|
|
|
if (item->state().testFlag(BoostTestTreeItem::Templated))
|
|
|
|
|
tcName.append("<*");
|
2019-10-14 09:54:28 +02:00
|
|
|
else if (item->state().testFlag(BoostTestTreeItem::Parameterized))
|
2020-09-21 17:12:20 +02:00
|
|
|
tcName.append("_*");
|
2019-06-03 14:47:54 +02:00
|
|
|
tcName = handleSpecialFunctionNames(tcName);
|
2018-12-07 10:00:23 +01:00
|
|
|
testCasesForProjectFile[item->proFile()].testCases.append(
|
|
|
|
|
item->prependWithParentsSuitePaths(tcName));
|
|
|
|
|
testCasesForProjectFile[item->proFile()].internalTargets.unite(item->internalTargets());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto end = testCasesForProjectFile.cend();
|
|
|
|
|
for (auto it = testCasesForProjectFile.cbegin(); it != end; ++it) {
|
2019-10-22 08:38:28 +02:00
|
|
|
for (const QString &target : it.value().internalTargets) {
|
2020-03-26 10:11:39 +01:00
|
|
|
BoostTestConfiguration *config = new BoostTestConfiguration(framework());
|
2019-10-22 08:38:28 +02:00
|
|
|
config->setProject(project);
|
|
|
|
|
config->setProjectFile(it.key());
|
|
|
|
|
config->setTestCases(it.value().testCases);
|
|
|
|
|
config->setInternalTarget(target);
|
|
|
|
|
result.append(config);
|
|
|
|
|
}
|
2018-12-07 10:00:23 +01:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 11:37:37 +02:00
|
|
|
QList<ITestConfiguration *> BoostTestTreeItem::getSelectedTestConfigurations() const
|
2020-09-11 14:30:15 +02:00
|
|
|
{
|
|
|
|
|
return getTestConfigurations([](BoostTestTreeItem *it) {
|
|
|
|
|
return it->checked() == Qt::Checked;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 11:37:37 +02:00
|
|
|
QList<ITestConfiguration *> BoostTestTreeItem::getFailedTestConfigurations() const
|
2020-09-11 14:30:15 +02:00
|
|
|
{
|
|
|
|
|
return getTestConfigurations([](BoostTestTreeItem *it) {
|
|
|
|
|
return it->data(0, FailedRole).toBool();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 11:37:37 +02:00
|
|
|
ITestConfiguration *BoostTestTreeItem::testConfiguration() const
|
2018-12-07 10:00:23 +01:00
|
|
|
{
|
|
|
|
|
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
|
|
|
|
|
QTC_ASSERT(project, return nullptr);
|
|
|
|
|
|
|
|
|
|
const Type itemType = type();
|
|
|
|
|
if (itemType == TestSuite || itemType == TestCase) {
|
|
|
|
|
QStringList testCases;
|
|
|
|
|
if (itemType == TestSuite) {
|
2020-10-12 14:11:10 +02:00
|
|
|
forFirstLevelChildItems([&testCases](TestTreeItem *child) {
|
2018-12-07 10:00:23 +01:00
|
|
|
QTC_ASSERT(child, return);
|
|
|
|
|
if (auto boostItem = static_cast<BoostTestTreeItem *>(child)) {
|
|
|
|
|
if (boostItem->enabled()) {
|
|
|
|
|
QString tcName = handleSpecialFunctionNames(boostItem->name());
|
|
|
|
|
if (boostItem->type() == TestSuite) // execute everything below a suite
|
|
|
|
|
tcName.append("/*");
|
2019-10-14 09:54:28 +02:00
|
|
|
else if (boostItem->state().testFlag(BoostTestTreeItem::Parameterized))
|
2020-09-21 17:12:20 +02:00
|
|
|
tcName.append("_*");
|
2019-06-03 14:47:54 +02:00
|
|
|
else if (boostItem->state().testFlag(BoostTestTreeItem::Templated))
|
|
|
|
|
tcName.append("<*");
|
2018-12-07 10:00:23 +01:00
|
|
|
testCases.append(boostItem->prependWithParentsSuitePaths(tcName));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
2019-06-03 14:47:54 +02:00
|
|
|
QString tcName = name();
|
|
|
|
|
if (state().testFlag(BoostTestTreeItem::Templated))
|
|
|
|
|
tcName.append("<*");
|
2019-10-14 09:54:28 +02:00
|
|
|
else if (state().testFlag(BoostTestTreeItem::Parameterized))
|
2020-09-21 17:12:20 +02:00
|
|
|
tcName.append("_*");
|
2019-06-03 14:47:54 +02:00
|
|
|
testCases.append(prependWithParentsSuitePaths(handleSpecialFunctionNames(tcName)));
|
2018-12-07 10:00:23 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-26 10:11:39 +01:00
|
|
|
BoostTestConfiguration *config = new BoostTestConfiguration(framework());
|
2018-12-07 10:00:23 +01:00
|
|
|
config->setProjectFile(proFile());
|
|
|
|
|
config->setProject(project);
|
|
|
|
|
config->setTestCases(testCases);
|
|
|
|
|
config->setInternalTargets(internalTargets());
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 11:37:37 +02:00
|
|
|
ITestConfiguration *BoostTestTreeItem::debugConfiguration() const
|
2018-12-07 10:00:23 +01:00
|
|
|
{
|
|
|
|
|
BoostTestConfiguration *config = static_cast<BoostTestConfiguration *>(testConfiguration());
|
|
|
|
|
if (config)
|
|
|
|
|
config->setRunMode(TestRunMode::Debug);
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString BoostTestTreeItem::nameSuffix() const
|
|
|
|
|
{
|
|
|
|
|
static QString markups[] = {QCoreApplication::translate("BoostTestTreeItem", "parameterized"),
|
2019-06-03 14:47:54 +02:00
|
|
|
QCoreApplication::translate("BoostTestTreeItem", "fixture"),
|
|
|
|
|
QCoreApplication::translate("BoostTestTreeItem", "templated")};
|
2018-12-07 10:00:23 +01:00
|
|
|
QString suffix;
|
|
|
|
|
if (m_state & Parameterized)
|
|
|
|
|
suffix = QString(" [") + markups[0];
|
|
|
|
|
if (m_state & Fixture)
|
|
|
|
|
suffix += (suffix.isEmpty() ? QString(" [") : QString(", ")) + markups[1];
|
2019-06-03 14:47:54 +02:00
|
|
|
if (m_state & Templated)
|
|
|
|
|
suffix += (suffix.isEmpty() ? QString(" [") : QString(", ")) + markups[2];
|
2018-12-07 10:00:23 +01:00
|
|
|
if (!suffix.isEmpty())
|
|
|
|
|
suffix += ']';
|
|
|
|
|
return suffix;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BoostTestTreeItem::enabled() const
|
|
|
|
|
{
|
|
|
|
|
if (m_state & ExplicitlyEnabled)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (m_state & Disabled)
|
|
|
|
|
return false;
|
|
|
|
|
|
2020-03-05 09:47:02 +01:00
|
|
|
if (type() == Root)
|
|
|
|
|
return true;
|
|
|
|
|
|
2018-12-07 10:00:23 +01:00
|
|
|
const TestTreeItem *parent = parentItem();
|
|
|
|
|
if (parent && parent->type() == TestSuite) // take test suites into account
|
|
|
|
|
return static_cast<const BoostTestTreeItem *>(parent)->enabled();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestTreeItem *BoostTestTreeItem::findChildByNameStateAndFile(const QString &name,
|
|
|
|
|
BoostTestTreeItem::TestStates state,
|
|
|
|
|
const QString &proFile) const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<TestTreeItem *>(
|
|
|
|
|
findAnyChild([name, state, proFile](const Utils::TreeItem *other){
|
|
|
|
|
const BoostTestTreeItem *boostItem = static_cast<const BoostTestTreeItem *>(other);
|
|
|
|
|
return boostItem->proFile() == proFile && boostItem->fullName() == name
|
|
|
|
|
&& boostItem->state() == state;
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BoostTestTreeItem::modifyTestContent(const BoostTestParseResult *result)
|
|
|
|
|
{
|
|
|
|
|
bool hasBeenModified = modifyLineAndColumn(result);
|
|
|
|
|
|
|
|
|
|
if (m_state != result->state) {
|
|
|
|
|
m_state = result->state;
|
|
|
|
|
hasBeenModified = true;
|
|
|
|
|
}
|
|
|
|
|
if (m_fullName != result->name) {
|
|
|
|
|
m_fullName = result->name;
|
|
|
|
|
hasBeenModified = true;
|
|
|
|
|
}
|
|
|
|
|
return hasBeenModified;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Autotest
|