Commit 2f8b4b3f authored by Christian Stenger's avatar Christian Stenger
Browse files

AutoTest: Move test framework related code...



...into files and respective sub folders.

Change-Id: Ic80d693bd73993a6e74b6d422349e47276e8cb6e
Reviewed-by: default avatarDavid Schulz <david.schulz@theqtcompany.com>
parent 6c18ed50
......@@ -10,7 +10,6 @@ SOURCES += \
testtreeview.cpp \
testtreemodel.cpp \
testtreeitem.cpp \
testvisitor.cpp \
testcodeparser.cpp \
autotestplugin.cpp \
testrunner.cpp \
......@@ -23,13 +22,29 @@ SOURCES += \
testsettings.cpp \
testsettingspage.cpp \
testnavigationwidget.cpp \
testoutputreader.cpp
testoutputreader.cpp \
gtest/googletestconfiguration.cpp \
gtest/googletestparser.cpp \
gtest/googletesttreeitem.cpp \
gtest/gtestresult.cpp \
gtest/gtestoutputreader.cpp \
gtest/gtestvisitors.cpp \
qtest/autotesttreeitem.cpp \
qtest/qttestvisitors.cpp \
qtest/qttestconfiguration.cpp \
qtest/qttestoutputreader.cpp \
qtest/qttestresult.cpp \
qtest/qttestparser.cpp \
quick/quicktestconfiguration.cpp \
quick/quicktestparser.cpp \
quick/quicktesttreeitem.cpp \
quick/quicktestvisitors.cpp
HEADERS += \
testtreeview.h \
testtreemodel.h \
testtreeitem.h \
testvisitor.h \
testcodeparser.h \
autotestplugin.h \
autotest_global.h \
......@@ -46,7 +61,27 @@ HEADERS += \
testsettingspage.h \
testnavigationwidget.h \
testoutputreader.h \
autotesticons.h
autotesticons.h \
itestparser.h \
gtest/googletestconfiguration.h \
gtest/googletestparser.h \
gtest/googletesttreeitem.h \
gtest/gtestoutputreader.h \
gtest/gtestresult.h \
gtest/gtest_utils.h \
gtest/gtestvisitors.h \
qtest/autotesttreeitem.h \
qtest/qttest_utils.h \
qtest/qttestresult.h \
qtest/qttestvisitors.h \
qtest/qttestconfiguration.h \
qtest/qttestoutputreader.h \
qtest/qttestparser.h \
quick/quicktestconfiguration.h \
quick/quicktestparser.h \
quick/quicktesttreeitem.h \
quick/quicktest_utils.h \
quick/quicktestvisitors.h
RESOURCES += \
autotest.qrc
......
......@@ -71,6 +71,27 @@ QtcPlugin {
"testoutputreader.h",
]
Group {
name: "QtTest framework files"
files: [
"qtest/*"
]
}
Group {
name: "Quick Test framework files"
files: [
"quick/*"
]
}
Group {
name: "Google Test framework files"
files: [
"gtest/*"
]
}
Group {
name: "Test sources"
condition: project.testsEnabled
......
......@@ -25,8 +25,11 @@
#pragma once
#include <coreplugin/editormanager/editormanager.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cppworkingcopy.h>
#include <cpptools/projectpart.h>
#include <utils/textfileformat.h>
#include <QStringList>
......@@ -36,37 +39,6 @@ namespace Internal {
class TestUtils
{
public:
static bool isGTestMacro(const QString &macro)
{
static QStringList valid = {
QStringLiteral("TEST"), QStringLiteral("TEST_F"), QStringLiteral("TEST_P"),
QStringLiteral("TYPED_TEST"), QStringLiteral("TYPED_TEST_P")
};
return valid.contains(macro);
}
static bool isGTestParameterized(const QString &macro)
{
return macro == QStringLiteral("TEST_P") || macro == QStringLiteral("TYPED_TEST_P");
}
static bool isGTestTyped(const QString &macro)
{
return macro == QStringLiteral("TYPED_TEST") || macro == QStringLiteral("TYPED_TEST_P");
}
static bool isQTestMacro(const QByteArray &macro)
{
static QByteArrayList valid = {"QTEST_MAIN", "QTEST_APPLESS_MAIN", "QTEST_GUILESS_MAIN"};
return valid.contains(macro);
}
static bool isQuickTestMacro(const QByteArray &macro)
{
static const QByteArrayList valid = {"QUICK_TEST_MAIN", "QUICK_TEST_OPENGL_MAIN"};
return valid.contains(macro);
}
static QString getCMakeDisplayNameIfNecessary(const QString &filePath, const QString &proFile)
{
static const QString CMAKE_LISTS = QLatin1String("CMakeLists.txt");
......@@ -80,6 +52,24 @@ public:
return QString();
}
static QByteArray getFileContent(QString filePath)
{
QByteArray fileContent;
CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
CppTools::WorkingCopy wc = cppMM->workingCopy();
if (wc.contains(filePath)) {
fileContent = wc.source(filePath);
} else {
QString error;
const QTextCodec *codec = Core::EditorManager::defaultTextCodec();
if (Utils::TextFileFormat::readFileUTF8(filePath, codec, &fileContent, &error)
!= Utils::TextFileFormat::ReadSuccess) {
qDebug() << "Failed to read file" << filePath << ":" << error;
}
}
return fileContent;
}
};
} // namespace Internal
......
......@@ -38,7 +38,6 @@ const char AUTOTEST_ID[] = "AutoTest.ATP";
const char AUTOTEST_CONTEXT[] = "Auto Tests";
const char TASK_INDEX[] = "AutoTest.Task.Index";
const char TASK_PARSE[] = "AutoTest.Task.Parse";
const char UNNAMED_QUICKTESTS[] = QT_TR_NOOP("<unnamed>");
const char AUTOTEST_SETTINGS_CATEGORY[] = "ZY.Tests";
} // namespace Constants
......
/****************************************************************************
**
** 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 "googletestconfiguration.h"
#include "gtestoutputreader.h"
#include "../testsettings.h"
namespace Autotest {
namespace Internal {
TestOutputReader *GoogleTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const
{
return new GTestOutputReader(fi, app, buildDirectory());
}
QStringList GoogleTestConfiguration::argumentsForTestRunner(const TestSettings &settings) const
{
QStringList arguments;
const QStringList &testSets = testCases();
if (testSets.size())
arguments << QLatin1String("--gtest_filter=") + testSets.join(QLatin1Char(':'));
if (settings.gtestRunDisabled)
arguments << QLatin1String("--gtest_also_run_disabled_tests");
if (settings.gtestRepeat)
arguments << QString::fromLatin1("--gtest_repeat=%1").arg(settings.gtestIterations);
if (settings.gtestShuffle) {
arguments << QLatin1String("--gtest_shuffle")
<< QString::fromLatin1("--gtest_random_seed=%1").arg(settings.gtestSeed);
}
return arguments;
}
} // namespace Internal
} // namespace Autotest
/****************************************************************************
**
** 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.
**
****************************************************************************/
#pragma once
#include "../testconfiguration.h"
namespace Autotest {
namespace Internal {
class GoogleTestConfiguration : public TestConfiguration
{
public:
explicit GoogleTestConfiguration() {}
TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
QProcess *app) const override;
QStringList argumentsForTestRunner(const TestSettings &settings) const override;
};
} // namespace Internal
} // namespace Autotest
/****************************************************************************
**
** 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 "googletestparser.h"
#include "googletesttreeitem.h"
#include "gtestvisitors.h"
#include "gtest_utils.h"
#include "../autotest_utils.h"
namespace Autotest {
namespace Internal {
TestTreeItem *GoogleTestParseResult::createTestTreeItem() const
{
if (itemType == TestTreeItem::TestCase || itemType == TestTreeItem::TestFunctionOrSet)
return GoogleTestTreeItem::createTestItem(this);
return 0;
}
static bool includesGTest(const CPlusPlus::Document::Ptr &doc,
const CPlusPlus::Snapshot &snapshot)
{
const QString gtestH = QLatin1String("gtest/gtest.h");
foreach (const CPlusPlus::Document::Include &inc, doc->resolvedIncludes()) {
if (inc.resolvedFileName().endsWith(gtestH))
return true;
}
foreach (const QString &include, snapshot.allIncludesForDocument(doc->fileName())) {
if (include.endsWith(gtestH))
return true;
}
return false;
}
static bool hasGTestNames(const CPlusPlus::Document::Ptr &document)
{
foreach (const CPlusPlus::Document::MacroUse &macro, document->macroUses()) {
if (!macro.isFunctionLike())
continue;
if (GTestUtils::isGTestMacro(QLatin1String(macro.macro().name()))) {
const QVector<CPlusPlus::Document::Block> args = macro.arguments();
if (args.size() != 2)
continue;
return true;
}
}
return false;
}
static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
const CPlusPlus::Document::Ptr &doc,
const CPlusPlus::Snapshot &snapshot)
{
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
const QString &filePath = doc->fileName();
const QByteArray &fileContent = TestUtils::getFileContent(filePath);
CPlusPlus::Document::Ptr document = snapshot.preprocessedDocument(fileContent, filePath);
document->check();
CPlusPlus::AST *ast = document->translationUnit()->ast();
GTestVisitor visitor(document);
visitor.accept(ast);
QMap<GTestCaseSpec, GTestCodeLocationList> result = visitor.gtestFunctions();
QString proFile;
const QList<CppTools::ProjectPart::Ptr> &ppList = modelManager->projectPart(filePath);
if (ppList.size())
proFile = ppList.first()->projectFile;
foreach (const GTestCaseSpec &testSpec, result.keys()) {
GoogleTestParseResult *parseResult = new GoogleTestParseResult;
parseResult->itemType = TestTreeItem::TestCase;
parseResult->fileName = filePath;
parseResult->name = testSpec.testCaseName;
parseResult->parameterized = testSpec.parameterized;
parseResult->typed = testSpec.typed;
parseResult->disabled = testSpec.disabled;
parseResult->proFile = proFile;
foreach (const GTestCodeLocationAndType &location, result.value(testSpec)) {
GoogleTestParseResult *testSet = new GoogleTestParseResult;
testSet->name = location.m_name;
testSet->fileName = filePath;
testSet->line = location.m_line;
testSet->column = location.m_column;
testSet->disabled = location.m_state & GoogleTestTreeItem::Disabled;
testSet->itemType = location.m_type;
testSet->proFile = proFile;
parseResult->children.append(testSet);
}
futureInterface.reportResult(TestParseResultPtr(parseResult));
}
return !result.keys().isEmpty();
}
bool GoogleTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName)
{
if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
return false;
CPlusPlus::Document::Ptr document = m_cppSnapshot.find(fileName).value();
if (!includesGTest(document, m_cppSnapshot) || !hasGTestNames(document))
return false;
return handleGTest(futureInterface, document, m_cppSnapshot);
}
} // namespace Internal
} // namespace Autotest
/****************************************************************************
**
** 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.
**
****************************************************************************/
#pragma once
#include "../itestparser.h"
namespace Autotest {
namespace Internal {
class GoogleTestParseResult : public TestParseResult
{
public:
explicit GoogleTestParseResult() : TestParseResult(TestTreeModel::GoogleTest) {}
TestTreeItem *createTestTreeItem() const override;
bool parameterized = false;
bool typed = false;
bool disabled = false;
};
class GoogleTestParser : public CppParser
{
public:
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName) override;
};
} // namespace Internal
} // namespace Autotest
/****************************************************************************
**
** 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 "googletesttreeitem.h"
#include "googletestconfiguration.h"
#include "googletestparser.h"
#include "../autotest_utils.h"
#include <projectexplorer/session.h>
#include <utils/qtcassert.h>
namespace Autotest {
namespace Internal {
static QString gtestFilter(GoogleTestTreeItem::TestStates states)
{
if ((states & GoogleTestTreeItem::Parameterized) && (states & GoogleTestTreeItem::Typed))
return QLatin1String("*/%1/*.%2");
if (states & GoogleTestTreeItem::Parameterized)
return QLatin1String("*/%1.%2/*");
if (states & GoogleTestTreeItem::Typed)
return QLatin1String("%1/*.%2");
return QLatin1String("%1.%2");
}
GoogleTestTreeItem *GoogleTestTreeItem::createTestItem(const TestParseResult *result)
{
const GoogleTestParseResult *parseResult = static_cast<const GoogleTestParseResult *>(result);
GoogleTestTreeItem *item = new GoogleTestTreeItem(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 GoogleTestTreeItem::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 *GoogleTestTreeItem::testConfiguration() const
{
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
QTC_ASSERT(project, return 0);
GoogleTestConfiguration *config = 0;
switch (type()) {
case TestCase: {
const QString &testSpecifier = gtestFilter(state()).arg(name()).arg(QLatin1Char('*'));
if (int count = childCount()) {
config = new GoogleTestConfiguration;
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: {
GoogleTestTreeItem *parent = static_cast<GoogleTestTreeItem *>(parentItem());
if (!parent)
return 0;
const QString &testSpecifier = gtestFilter(parent->state()).arg(parent->name()).arg(name());
config = new GoogleTestConfiguration;
config->setTestCases(QStringList(testSpecifier));
config->setProFile(proFile());
config->setProject(project);
config->setDisplayName(
TestUtils::getCMakeDisplayNameIfNecessary(filePath(), parent->proFile()));
break;
}
default: