aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/autotest
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/autotest')
-rw-r--r--src/plugins/autotest/CMakeLists.txt80
-rw-r--r--src/plugins/autotest/autotest.pro20
-rw-r--r--src/plugins/autotest/autotest.qbs7
-rw-r--r--src/plugins/autotest/autotest.qrc5
-rw-r--r--src/plugins/autotest/autotesticons.h2
-rw-r--r--src/plugins/autotest/autotestplugin.cpp14
-rw-r--r--src/plugins/autotest/autotestplugin.h3
-rw-r--r--src/plugins/autotest/autotestunittests.cpp67
-rw-r--r--src/plugins/autotest/autotestunittests.h9
-rw-r--r--src/plugins/autotest/autotestunittests.qrc17
-rw-r--r--src/plugins/autotest/boost/boostcodeparser.cpp422
-rw-r--r--src/plugins/autotest/boost/boostcodeparser.h82
-rw-r--r--src/plugins/autotest/boost/boosttestconfiguration.cpp154
-rw-r--r--src/plugins/autotest/boost/boosttestconfiguration.h44
-rw-r--r--src/plugins/autotest/boost/boosttestconstants.h41
-rw-r--r--src/plugins/autotest/boost/boosttestframework.cpp76
-rw-r--r--src/plugins/autotest/boost/boosttestframework.h48
-rw-r--r--src/plugins/autotest/boost/boosttestoutputreader.cpp457
-rw-r--r--src/plugins/autotest/boost/boosttestoutputreader.h68
-rw-r--r--src/plugins/autotest/boost/boosttestparser.cpp184
-rw-r--r--src/plugins/autotest/boost/boosttestparser.h51
-rw-r--r--src/plugins/autotest/boost/boosttestresult.cpp76
-rw-r--r--src/plugins/autotest/boost/boosttestresult.h49
-rw-r--r--src/plugins/autotest/boost/boosttestsettings.cpp97
-rw-r--r--src/plugins/autotest/boost/boosttestsettings.h81
-rw-r--r--src/plugins/autotest/boost/boosttestsettingspage.cpp117
-rw-r--r--src/plugins/autotest/boost/boosttestsettingspage.h69
-rw-r--r--src/plugins/autotest/boost/boosttestsettingspage.ui163
-rw-r--r--src/plugins/autotest/boost/boosttesttreeitem.cpp365
-rw-r--r--src/plugins/autotest/boost/boosttesttreeitem.h107
-rw-r--r--src/plugins/autotest/gtest/gtestoutputreader.cpp129
-rw-r--r--src/plugins/autotest/gtest/gtestoutputreader.h8
-rw-r--r--src/plugins/autotest/gtest/gtestparser.cpp12
-rw-r--r--src/plugins/autotest/gtest/gtestresult.cpp45
-rw-r--r--src/plugins/autotest/gtest/gtestresult.h11
-rw-r--r--src/plugins/autotest/gtest/gtesttreeitem.cpp75
-rw-r--r--src/plugins/autotest/gtest/gtesttreeitem.h3
-rw-r--r--src/plugins/autotest/gtest/gtestvisitors.cpp2
-rw-r--r--src/plugins/autotest/images/data@2x.pngbin0 -> 1199 bytes
-rw-r--r--src/plugins/autotest/images/sort.pngbin139 -> 0 bytes
-rw-r--r--src/plugins/autotest/images/sort@2x.pngbin205 -> 0 bytes
-rw-r--r--src/plugins/autotest/images/suite.pngbin0 -> 306 bytes
-rw-r--r--src/plugins/autotest/images/suite@2x.pngbin0 -> 501 bytes
-rw-r--r--src/plugins/autotest/itestparser.cpp5
-rw-r--r--src/plugins/autotest/itestparser.h2
-rw-r--r--src/plugins/autotest/qtest/qttestoutputreader.cpp47
-rw-r--r--src/plugins/autotest/qtest/qttestoutputreader.h4
-rw-r--r--src/plugins/autotest/qtest/qttestparser.cpp4
-rw-r--r--src/plugins/autotest/qtest/qttestresult.cpp25
-rw-r--r--src/plugins/autotest/qtest/qttestresult.h1
-rw-r--r--src/plugins/autotest/qtest/qttesttreeitem.cpp20
-rw-r--r--src/plugins/autotest/qtest/qttesttreeitem.h2
-rw-r--r--src/plugins/autotest/qtest/qttestvisitors.cpp2
-rw-r--r--src/plugins/autotest/quick/quicktestparser.cpp4
-rw-r--r--src/plugins/autotest/quick/quicktesttreeitem.cpp24
-rw-r--r--src/plugins/autotest/quick/quicktesttreeitem.h2
-rw-r--r--src/plugins/autotest/quick/quicktestvisitors.cpp2
-rw-r--r--src/plugins/autotest/testcodeparser.cpp27
-rw-r--r--src/plugins/autotest/testconfiguration.cpp18
-rw-r--r--src/plugins/autotest/testconfiguration.h2
-rw-r--r--src/plugins/autotest/testeditormark.cpp2
-rw-r--r--src/plugins/autotest/testeditormark.h2
-rw-r--r--src/plugins/autotest/testnavigationwidget.cpp3
-rw-r--r--src/plugins/autotest/testoutputreader.cpp4
-rw-r--r--src/plugins/autotest/testoutputreader.h7
-rw-r--r--src/plugins/autotest/testresult.cpp141
-rw-r--r--src/plugins/autotest/testresult.h59
-rw-r--r--src/plugins/autotest/testresultdelegate.cpp12
-rw-r--r--src/plugins/autotest/testresultdelegate.h2
-rw-r--r--src/plugins/autotest/testresultmodel.cpp261
-rw-r--r--src/plugins/autotest/testresultmodel.h30
-rw-r--r--src/plugins/autotest/testresultspane.cpp81
-rw-r--r--src/plugins/autotest/testrunner.cpp118
-rw-r--r--src/plugins/autotest/testrunner.h3
-rw-r--r--src/plugins/autotest/testsettings.cpp15
-rw-r--r--src/plugins/autotest/testsettings.h5
-rw-r--r--src/plugins/autotest/testsettingspage.cpp160
-rw-r--r--src/plugins/autotest/testsettingspage.h5
-rw-r--r--src/plugins/autotest/testsettingspage.ui153
-rw-r--r--src/plugins/autotest/testtreeitem.cpp18
-rw-r--r--src/plugins/autotest/testtreeitem.h11
-rw-r--r--src/plugins/autotest/testtreemodel.cpp41
-rw-r--r--src/plugins/autotest/testtreemodel.h4
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/simple_boost.pro2
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/simple_boost.qbs5
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/src/main.cpp6
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/src/src.pro4
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/src/src.qbs6
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/deco/deco.pro8
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/deco/deco.qbs11
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/deco/enab.h23
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/deco/main.cpp21
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.cpp18
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.pro7
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.qbs11
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/params/main.cpp41
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/params/params.pro7
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/params/params.qbs11
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/tests.pro2
-rw-r--r--src/plugins/autotest/unit_test/simple_boost/tests/tests.qbs11
-rw-r--r--src/plugins/autotest/unit_test/simple_gt/tests/common/functions.js26
-rw-r--r--src/plugins/autotest/unit_test/simple_gt/tests/gt1/gt1.qbs12
-rw-r--r--src/plugins/autotest/unit_test/simple_gt/tests/gt2/gt2.qbs12
-rw-r--r--src/plugins/autotest/unit_test/simple_gt/tests/gt2/queuetest.h1
-rw-r--r--src/plugins/autotest/unit_test/simple_gt/tests/gt3/gt3.qbs12
-rw-r--r--src/plugins/autotest/unit_test/simple_gt/tests/gt3/main.cpp4
106 files changed, 3945 insertions, 904 deletions
diff --git a/src/plugins/autotest/CMakeLists.txt b/src/plugins/autotest/CMakeLists.txt
new file mode 100644
index 0000000000..a5291ce315
--- /dev/null
+++ b/src/plugins/autotest/CMakeLists.txt
@@ -0,0 +1,80 @@
+if (WITH_TESTS)
+ set(TEST_COMPONENT QmakeProjectManager QtSupport)
+endif()
+
+add_qtc_plugin(AutoTest
+ PLUGIN_DEPENDS Core CppTools Debugger ProjectExplorer QmlJSTools TextEditor ${TEST_COMPONENT}
+ SOURCES
+ autotest.qrc
+ autotest_global.h
+ autotestconstants.h
+ autotesticons.h
+ autotestplugin.cpp autotestplugin.h
+ autotestunittests.qrc
+ boost/boostcodeparser.cpp boost/boostcodeparser.h
+ boost/boosttestconfiguration.cpp boost/boosttestconfiguration.h
+ boost/boosttestconstants.h
+ boost/boosttestframework.cpp boost/boosttestframework.h
+ boost/boosttestoutputreader.cpp boost/boosttestoutputreader.h
+ boost/boosttestparser.cpp boost/boosttestparser.h
+ boost/boosttestresult.cpp boost/boosttestresult.h
+ boost/boosttestsettings.cpp boost/boosttestsettings.h
+ boost/boosttestsettingspage.cpp boost/boosttestsettingspage.h boost/boosttestsettingspage.ui
+ boost/boosttesttreeitem.cpp boost/boosttesttreeitem.h
+ gtest/gtest_utils.cpp gtest/gtest_utils.h
+ gtest/gtestconfiguration.cpp gtest/gtestconfiguration.h
+ gtest/gtestconstants.h
+ gtest/gtestframework.cpp gtest/gtestframework.h
+ gtest/gtestoutputreader.cpp gtest/gtestoutputreader.h
+ gtest/gtestparser.cpp gtest/gtestparser.h
+ gtest/gtestresult.cpp gtest/gtestresult.h
+ gtest/gtestsettings.cpp gtest/gtestsettings.h
+ gtest/gtestsettingspage.cpp gtest/gtestsettingspage.h gtest/gtestsettingspage.ui
+ gtest/gtesttreeitem.cpp gtest/gtesttreeitem.h
+ gtest/gtestvisitors.cpp gtest/gtestvisitors.h
+ iframeworksettings.h
+ itestframework.h
+ itestparser.cpp itestparser.h
+ itestsettingspage.h
+ qtest/qttest_utils.cpp qtest/qttest_utils.h
+ qtest/qttestconfiguration.cpp qtest/qttestconfiguration.h
+ qtest/qttestconstants.h
+ qtest/qttestframework.cpp qtest/qttestframework.h
+ qtest/qttestoutputreader.cpp qtest/qttestoutputreader.h
+ qtest/qttestparser.cpp qtest/qttestparser.h
+ qtest/qttestresult.cpp qtest/qttestresult.h
+ qtest/qttestsettings.cpp qtest/qttestsettings.h
+ qtest/qttestsettingspage.cpp qtest/qttestsettingspage.h qtest/qttestsettingspage.ui
+ qtest/qttesttreeitem.cpp qtest/qttesttreeitem.h
+ qtest/qttestvisitors.cpp qtest/qttestvisitors.h
+ quick/quicktest_utils.cpp quick/quicktest_utils.h
+ quick/quicktestconfiguration.cpp quick/quicktestconfiguration.h
+ quick/quicktestframework.cpp quick/quicktestframework.h
+ quick/quicktestparser.cpp quick/quicktestparser.h
+ quick/quicktesttreeitem.cpp quick/quicktesttreeitem.h
+ quick/quicktestvisitors.cpp quick/quicktestvisitors.h
+ testcodeparser.cpp testcodeparser.h
+ testconfiguration.cpp testconfiguration.h
+ testeditormark.cpp testeditormark.h
+ testframeworkmanager.cpp testframeworkmanager.h
+ testnavigationwidget.cpp testnavigationwidget.h
+ testoutputreader.cpp testoutputreader.h
+ testresult.cpp testresult.h
+ testresultdelegate.cpp testresultdelegate.h
+ testresultmodel.cpp testresultmodel.h
+ testresultspane.cpp testresultspane.h
+ testrunconfiguration.h
+ testrunner.cpp testrunner.h
+ testsettings.cpp testsettings.h
+ testsettingspage.cpp testsettingspage.h testsettingspage.ui
+ testtreeitem.cpp testtreeitem.h
+ testtreeitemdelegate.cpp testtreeitemdelegate.h
+ testtreemodel.cpp testtreemodel.h
+ testtreeview.cpp testtreeview.h
+ EXPLICIT_MOC boost/boosttestsettingspage.h
+)
+
+extend_qtc_plugin(AutoTest
+ CONDITION WITH_TESTS
+ SOURCES autotestunittests.cpp autotestunittests.h
+)
diff --git a/src/plugins/autotest/autotest.pro b/src/plugins/autotest/autotest.pro
index d8af2b75c7..22e2b594c9 100644
--- a/src/plugins/autotest/autotest.pro
+++ b/src/plugins/autotest/autotest.pro
@@ -49,6 +49,15 @@ SOURCES += \
quick/quicktestvisitors.cpp \
quick/quicktestframework.cpp \
quick/quicktest_utils.cpp \
+ boost/boostcodeparser.cpp \
+ boost/boosttestframework.cpp \
+ boost/boosttesttreeitem.cpp \
+ boost/boosttestparser.cpp \
+ boost/boosttestconfiguration.cpp \
+ boost/boosttestoutputreader.cpp \
+ boost/boosttestresult.cpp \
+ boost/boosttestsettings.cpp \
+ boost/boosttestsettingspage.cpp \
testframeworkmanager.cpp \
testeditormark.cpp
@@ -104,6 +113,16 @@ HEADERS += \
quick/quicktest_utils.h \
quick/quicktestvisitors.h \
quick/quicktestframework.h \
+ boost/boostcodeparser.h \
+ boost/boosttestframework.h \
+ boost/boosttestconstants.h \
+ boost/boosttesttreeitem.h \
+ boost/boosttestparser.h \
+ boost/boosttestconfiguration.h \
+ boost/boosttestoutputreader.h \
+ boost/boosttestresult.h \
+ boost/boosttestsettingspage.h \
+ boost/boosttestsettings.h \
testframeworkmanager.h \
testrunconfiguration.h \
itestsettingspage.h \
@@ -114,6 +133,7 @@ RESOURCES += \
FORMS += \
testsettingspage.ui \
+ boost/boosttestsettingspage.ui \
qtest/qttestsettingspage.ui \
gtest/gtestsettingspage.ui
diff --git a/src/plugins/autotest/autotest.qbs b/src/plugins/autotest/autotest.qbs
index b25a27ce9c..9d31d53646 100644
--- a/src/plugins/autotest/autotest.qbs
+++ b/src/plugins/autotest/autotest.qbs
@@ -102,6 +102,13 @@ QtcPlugin {
}
Group {
+ name: "Boost Test framework files"
+ files: [
+ "boost/*"
+ ]
+ }
+
+ Group {
name: "Test sources"
condition: qtc.testsEnabled
files: [
diff --git a/src/plugins/autotest/autotest.qrc b/src/plugins/autotest/autotest.qrc
index 0c3a24d7ac..51d19022da 100644
--- a/src/plugins/autotest/autotest.qrc
+++ b/src/plugins/autotest/autotest.qrc
@@ -2,8 +2,6 @@
<qresource prefix="/autotest">
<file>images/settingscategory_autotest.png</file>
<file>images/settingscategory_autotest@2x.png</file>
- <file>images/sort.png</file>
- <file>images/sort@2x.png</file>
<file>images/leafsort.png</file>
<file>images/leafsort@2x.png</file>
<file>images/benchmark.png</file>
@@ -13,11 +11,14 @@
<file>images/runselected_tickmarks.png</file>
<file>images/runselected_tickmarks@2x.png</file>
<file>images/data.png</file>
+ <file>images/data@2x.png</file>
<file>images/text.png</file>
<file>images/text@2x.png</file>
<file>images/visual.png</file>
<file>images/visual@2x.png</file>
<file>images/run_file.png</file>
<file>images/run_file@2x.png</file>
+ <file>images/suite.png</file>
+ <file>images/suite@2x.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/autotest/autotesticons.h b/src/plugins/autotest/autotesticons.h
index 83bffffeb0..c8bfb63bbf 100644
--- a/src/plugins/autotest/autotesticons.h
+++ b/src/plugins/autotest/autotesticons.h
@@ -30,8 +30,6 @@
namespace Autotest {
namespace Icons {
-const Utils::Icon SORT_ALPHABETICALLY({
- {":/autotest/images/sort.png", Utils::Theme::IconsBaseColor}});
const Utils::Icon SORT_NATURALLY({
{":/autotest/images/leafsort.png", Utils::Theme::IconsBaseColor}});
const Utils::Icon RUN_SELECTED_OVERLAY({
diff --git a/src/plugins/autotest/autotestplugin.cpp b/src/plugins/autotest/autotestplugin.cpp
index 9a513bd2d4..5f90f33aca 100644
--- a/src/plugins/autotest/autotestplugin.cpp
+++ b/src/plugins/autotest/autotestplugin.cpp
@@ -40,6 +40,7 @@
#include "qtest/qttestframework.h"
#include "quick/quicktestframework.h"
#include "gtest/gtestframework.h"
+#include "boost/boosttestframework.h"
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
@@ -176,6 +177,7 @@ bool AutotestPlugin::initialize(const QStringList &arguments, QString *errorStri
m_frameworkManager->registerTestFramework(new QtTestFramework);
m_frameworkManager->registerTestFramework(new QuickTestFramework);
m_frameworkManager->registerTestFramework(new GTestFramework);
+ m_frameworkManager->registerTestFramework(new BoostTestFramework);
m_frameworkManager->synchronizeSettings(ICore::settings());
m_testSettingPage = new TestSettingsPage(m_settings);
@@ -248,7 +250,7 @@ void AutotestPlugin::onRunFileTriggered()
if (!document)
return;
- const Utils::FileName &fileName = document->filePath();
+ const Utils::FilePath &fileName = document->filePath();
if (fileName.isEmpty())
return;
@@ -349,9 +351,15 @@ void AutotestPlugin::clearChoiceCache()
s_instance->m_runconfigCache.clear();
}
-QList<QObject *> AutotestPlugin::createTestObjects() const
+void AutotestPlugin::popupResultsPane()
{
- QList<QObject *> tests;
+ if (s_instance)
+ s_instance->m_resultsPane->popup(Core::IOutputPane::NoModeSwitch);
+}
+
+QVector<QObject *> AutotestPlugin::createTestObjects() const
+{
+ QVector<QObject *> tests;
#ifdef WITH_TESTS
tests << new AutoTestUnitTests(TestTreeModel::instance());
#endif
diff --git a/src/plugins/autotest/autotestplugin.h b/src/plugins/autotest/autotestplugin.h
index dcbdb5ddde..c846d3e0b0 100644
--- a/src/plugins/autotest/autotestplugin.h
+++ b/src/plugins/autotest/autotestplugin.h
@@ -71,6 +71,7 @@ public:
static void cacheRunConfigChoice(const QString &buildTargetKey, const ChoicePair &choice);
static ChoicePair cachedChoiceFor(const QString &buildTargetKey);
static void clearChoiceCache();
+ static void popupResultsPane();
private:
void initializeMenuEntries();
@@ -78,7 +79,7 @@ private:
void onRunSelectedTriggered();
void onRunFileTriggered();
void onRunUnderCursorTriggered(TestRunMode mode);
- QList<QObject *> createTestObjects() const override;
+ QVector<QObject *> createTestObjects() const override;
const QSharedPointer<TestSettings> m_settings;
TestFrameworkManager *m_frameworkManager = nullptr;
TestSettingsPage *m_testSettingPage = nullptr;
diff --git a/src/plugins/autotest/autotestunittests.cpp b/src/plugins/autotest/autotestunittests.cpp
index 706824566c..614a61a6c2 100644
--- a/src/plugins/autotest/autotestunittests.cpp
+++ b/src/plugins/autotest/autotestunittests.cpp
@@ -39,6 +39,7 @@
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/toolchain.h>
+#include <QFileInfo>
#include <QSignalSpy>
#include <QTest>
@@ -53,9 +54,7 @@ namespace Internal {
AutoTestUnitTests::AutoTestUnitTests(TestTreeModel *model, QObject *parent)
: QObject(parent),
- m_model(model),
- m_tmpDir(nullptr),
- m_isQt4(false)
+ m_model(model)
{
}
@@ -64,16 +63,27 @@ void AutoTestUnitTests::initTestCase()
const QList<Kit *> allKits = KitManager::kits();
if (allKits.count() != 1)
QSKIP("This test requires exactly one kit to be present");
- if (auto qtVersion = QtSupport::QtKitInformation::qtVersion(allKits.first()))
+ if (auto qtVersion = QtSupport::QtKitAspect::qtVersion(allKits.first()))
m_isQt4 = qtVersion->qtVersionString().startsWith('4');
else
QSKIP("Could not figure out which Qt version is used for default kit.");
- const ToolChain * const toolchain = ToolChainKitInformation::toolChain(allKits.first(),
+ const ToolChain * const toolchain = ToolChainKitAspect::toolChain(allKits.first(),
ProjectExplorer::Constants::CXX_LANGUAGE_ID);
if (!toolchain)
QSKIP("This test requires that there is a kit with a toolchain.");
m_tmpDir = new CppTools::Tests::TemporaryCopiedDir(":/unit_test");
+
+ if (!qgetenv("BOOST_INCLUDE_DIR").isEmpty()) {
+ m_checkBoost = true;
+ } else {
+ if (Utils::HostOsInfo::isLinuxHost()
+ && (QFileInfo::exists("/usr/include/boost/version.hpp")
+ || QFileInfo::exists("/usr/local/include/boost/version.hpp"))) {
+ qDebug() << "Found boost at system level - will run boost parser test.";
+ m_checkBoost = true;
+ }
+ }
}
void AutoTestUnitTests::cleanupTestCase()
@@ -218,6 +228,7 @@ void AutoTestUnitTests::testCodeParserGTest()
QCOMPARE(m_model->namedQuickTestsCount(), 0);
QCOMPARE(m_model->unnamedQuickTestsCount(), 0);
QCOMPARE(m_model->dataTagsCount(), 0);
+ QCOMPARE(m_model->boostTestNamesCount(), 0);
}
void AutoTestUnitTests::testCodeParserGTest_data()
@@ -229,5 +240,51 @@ void AutoTestUnitTests::testCodeParserGTest_data()
<< QString(m_tmpDir->path() + "/simple_gt/simple_gt.qbs");
}
+void AutoTestUnitTests::testCodeParserBoostTest()
+{
+ if (!m_checkBoost)
+ QSKIP("This test needs boost - set BOOST_INCLUDE_DIR (or have it installed)");
+
+ QFETCH(QString, projectFilePath);
+ CppTools::Tests::ProjectOpenerAndCloser projectManager;
+ CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
+ QVERIFY(projectInfo.isValid());
+
+ QSignalSpy parserSpy(m_model->parser(), SIGNAL(parsingFinished()));
+ QSignalSpy modelUpdateSpy(m_model, SIGNAL(sweepingDone()));
+ QVERIFY(parserSpy.wait(20000));
+ QVERIFY(modelUpdateSpy.wait());
+
+ QCOMPARE(m_model->boostTestNamesCount(), 5);
+
+ QMultiMap<QString, int> expectedSuitesAndTests;
+ expectedSuitesAndTests.insert(QStringLiteral("Master Test Suite"), 2); // decorators w/o suite
+ expectedSuitesAndTests.insert(QStringLiteral("Master Test Suite"), 2); // fixtures
+ expectedSuitesAndTests.insert(QStringLiteral("Master Test Suite"), 3); // functions
+ expectedSuitesAndTests.insert(QStringLiteral("Suite1"), 4);
+ expectedSuitesAndTests.insert(QStringLiteral("SuiteOuter"), 5); // 2 sub suites + 3 tests
+
+ QMultiMap<QString, int> foundNamesAndSets = m_model->boostTestSuitesAndTests();
+ QCOMPARE(expectedSuitesAndTests.size(), foundNamesAndSets.size());
+ for (const QString &name : expectedSuitesAndTests.keys())
+ QCOMPARE(expectedSuitesAndTests.values(name), foundNamesAndSets.values(name));
+
+ // check also that no Qt related tests have been found
+ QCOMPARE(m_model->autoTestsCount(), 0);
+ QCOMPARE(m_model->namedQuickTestsCount(), 0);
+ QCOMPARE(m_model->unnamedQuickTestsCount(), 0);
+ QCOMPARE(m_model->dataTagsCount(), 0);
+ QCOMPARE(m_model->gtestNamesCount(), 0);
+}
+
+void AutoTestUnitTests::testCodeParserBoostTest_data()
+{
+ QTest::addColumn<QString>("projectFilePath");
+ QTest::newRow("simpleBoostTest")
+ << QString(m_tmpDir->path() + "/simple_boost/simple_boost.pro");
+ QTest::newRow("simpleBoostTestQbs")
+ << QString(m_tmpDir->path() + "/simple_boost/simple_boost.qbs");
+}
+
} // namespace Internal
} // namespace Autotest
diff --git a/src/plugins/autotest/autotestunittests.h b/src/plugins/autotest/autotestunittests.h
index 1d0e0b397b..3b464fc709 100644
--- a/src/plugins/autotest/autotestunittests.h
+++ b/src/plugins/autotest/autotestunittests.h
@@ -51,11 +51,14 @@ private slots:
void testCodeParserSwitchStartup_data();
void testCodeParserGTest();
void testCodeParserGTest_data();
+ void testCodeParserBoostTest();
+ void testCodeParserBoostTest_data();
private:
- TestTreeModel *m_model;
- CppTools::Tests::TemporaryCopiedDir *m_tmpDir;
- bool m_isQt4;
+ TestTreeModel *m_model = nullptr;
+ CppTools::Tests::TemporaryCopiedDir *m_tmpDir = nullptr;
+ bool m_isQt4 = false;
+ bool m_checkBoost = false;
};
} // namespace Internal
diff --git a/src/plugins/autotest/autotestunittests.qrc b/src/plugins/autotest/autotestunittests.qrc
index 68285166cd..13db89f567 100644
--- a/src/plugins/autotest/autotestunittests.qrc
+++ b/src/plugins/autotest/autotestunittests.qrc
@@ -72,5 +72,22 @@
<file>unit_test/mixed_atp/tests/auto/quickauto3/quickauto3.qbs</file>
<file>unit_test/mixed_atp/tests/auto/quickauto3/tst_test1.qml</file>
<file>unit_test/mixed_atp/tests/auto/quickauto3/tst_test2.qml</file>
+ <file>unit_test/simple_boost/simple_boost.pro</file>
+ <file>unit_test/simple_boost/simple_boost.qbs</file>
+ <file>unit_test/simple_boost/src/main.cpp</file>
+ <file>unit_test/simple_boost/src/src.pro</file>
+ <file>unit_test/simple_boost/src/src.qbs</file>
+ <file>unit_test/simple_boost/tests/tests.pro</file>
+ <file>unit_test/simple_boost/tests/tests.qbs</file>
+ <file>unit_test/simple_boost/tests/deco/deco.pro</file>
+ <file>unit_test/simple_boost/tests/deco/deco.qbs</file>
+ <file>unit_test/simple_boost/tests/deco/enab.h</file>
+ <file>unit_test/simple_boost/tests/deco/main.cpp</file>
+ <file>unit_test/simple_boost/tests/fix/fix.cpp</file>
+ <file>unit_test/simple_boost/tests/fix/fix.pro</file>
+ <file>unit_test/simple_boost/tests/fix/fix.qbs</file>
+ <file>unit_test/simple_boost/tests/params/main.cpp</file>
+ <file>unit_test/simple_boost/tests/params/params.pro</file>
+ <file>unit_test/simple_boost/tests/params/params.qbs</file>
</qresource>
</RCC>
diff --git a/src/plugins/autotest/boost/boostcodeparser.cpp b/src/plugins/autotest/boost/boostcodeparser.cpp
new file mode 100644
index 0000000000..79c612285b
--- /dev/null
+++ b/src/plugins/autotest/boost/boostcodeparser.cpp
@@ -0,0 +1,422 @@
+/****************************************************************************
+**
+** 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 "boostcodeparser.h"
+#include "boosttestconstants.h"
+
+#include <cplusplus/Overview.h>
+#include <cplusplus/Token.h>
+#include <utils/qtcassert.h>
+
+namespace Autotest {
+namespace Internal {
+
+using namespace CPlusPlus;
+
+BoostCodeParser::BoostCodeParser(const QByteArray &source, const LanguageFeatures &features,
+ const Document::Ptr &doc, const Snapshot &snapshot)
+ : m_source(source)
+ , m_features(features)
+ , m_doc(doc)
+ , m_snapshot(snapshot)
+ , m_lookupContext(m_doc, m_snapshot)
+{
+ m_typeOfExpression.init(m_doc, m_snapshot);
+}
+
+static BoostTestCodeLocationAndType locationAndTypeFromToken(const Token &tkn,
+ const QByteArray &src,
+ BoostTestTreeItem::TestStates state,
+ const BoostTestInfoList &suitesStates)
+{
+ BoostTestCodeLocationAndType locationAndType;
+ locationAndType.m_name = QString::fromUtf8(src.mid(int(tkn.bytesBegin()), int(tkn.bytes())));
+ locationAndType.m_type = TestTreeItem::TestCase;
+ locationAndType.m_line = tkn.lineno;
+ locationAndType.m_column = 0;
+ locationAndType.m_state = state;
+ if (suitesStates.isEmpty()) {
+ // should we handle renaming of master suite?
+ BoostTestInfo dummy{QString(BoostTest::Constants::BOOST_MASTER_SUITE),
+ BoostTestTreeItem::Enabled, 0};
+ locationAndType.m_suitesState.append(dummy);
+ } else {
+ locationAndType.m_suitesState.append(suitesStates);
+ }
+ return locationAndType;
+}
+
+static Tokens tokensForSource(const QByteArray &source, const LanguageFeatures &features)
+{
+ CPlusPlus::SimpleLexer lexer;
+ lexer.setPreprocessorMode(false); // or true? does not make a difference so far..
+ lexer.setLanguageFeatures(features);
+ return lexer(QString::fromUtf8(source));
+}
+
+BoostTestCodeLocationList BoostCodeParser::findTests()
+{
+ m_tokens = tokensForSource(m_source, m_features);
+ m_currentIndex = 0;
+ for ( ; m_currentIndex < m_tokens.size(); ++m_currentIndex) {
+ const Token &token = m_tokens.at(m_currentIndex);
+
+ if (token.kind() == T_IDENTIFIER)
+ handleIdentifier();
+
+ }
+ return m_testCases;
+}
+
+void BoostCodeParser::handleIdentifier()
+{
+ QTC_ASSERT(m_currentIndex < m_tokens.size(), return);
+ const Token &token = m_tokens.at(m_currentIndex);
+ const QByteArray &identifier = m_source.mid(int(token.bytesBegin()), int(token.bytes()));
+
+ if (identifier == "BOOST_AUTO_TEST_SUITE") {
+ handleSuiteBegin(false);
+ } else if (identifier == "BOOST_FIXTURE_TEST_SUITE") {
+ handleSuiteBegin(true);
+ } else if (identifier == "BOOST_AUTO_TEST_SUITE_END") {
+ handleSuiteEnd();
+ } else if (identifier == "BOOST_TEST_CASE") {
+ handleTestCase(TestCaseType::Functions);
+ } else if (identifier == "BOOST_PARAM_TEST_CASE") {
+ handleTestCase(TestCaseType::Parameter);
+ } else if (identifier == "BOOST_AUTO_TEST_CASE") {
+ handleTestCase(TestCaseType::Auto);
+ } else if (identifier == "BOOST_FIXTURE_TEST_CASE") {
+ handleTestCase(TestCaseType::Fixture);
+ } else if (identifier == "BOOST_DATA_TEST_CASE") {
+ handleTestCase(TestCaseType::Data);
+ } else if (identifier == "BOOST_DATA_TEST_CASE_F") {
+ m_currentState.setFlag(BoostTestTreeItem::Fixture);
+ handleTestCase(TestCaseType::Data);
+ } else if (identifier == "BOOST_AUTO_TEST_CASE_TEMPLATE") {
+ m_currentState.setFlag(BoostTestTreeItem::Templated);
+ handleTestCase(TestCaseType::Auto);
+ } else if (identifier == "BOOST_FIXTURE_TEST_CASE_TEMPLATE") {
+ m_currentState.setFlag(BoostTestTreeItem::Fixture);
+ m_currentState.setFlag(BoostTestTreeItem::Templated);
+ handleTestCase(TestCaseType::Auto);
+ } else if (identifier == "BOOST_TEST_DECORATOR") {
+ handleDecorator();
+ }
+}
+
+void BoostCodeParser::handleSuiteBegin(bool isFixture)
+{
+ m_currentSuite.clear();
+ if (!skipCommentsUntil(T_LPAREN))
+ return;
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return;
+
+ const Token &token = m_tokens.at(m_currentIndex);
+ const QByteArray &identifier = m_source.mid(int(token.bytesBegin()), int(token.bytes()));
+ m_lineNo = token.lineno;
+ m_currentSuite = QString::fromUtf8(identifier);
+ if (!m_suites.isEmpty())
+ m_currentSuite.prepend(m_suites.last().fullName + '/');
+
+ if (isFixture) { // fixture suites have a (fixture) class name as 2nd parameter
+ m_currentState.setFlag(BoostTestTreeItem::Fixture);
+ if (!skipCommentsUntil(T_COMMA))
+ return;
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return;
+ }
+
+ if (!skipCommentsUntil(T_COMMA)) {
+ if (skipCommentsUntil(T_RPAREN)) {
+ // we have no decorators (or we have them before this macro)
+ m_suites << BoostTestInfo{m_currentSuite, m_currentState, m_lineNo};
+ m_currentState = BoostTestTreeItem::Enabled;
+ }
+ } else {
+ handleDecorators();
+ m_suites << BoostTestInfo{m_currentSuite, m_currentState, m_lineNo};
+ m_currentState = BoostTestTreeItem::Enabled;
+ }
+}
+
+void BoostCodeParser::handleSuiteEnd()
+{
+ if (!skipCommentsUntil(T_LPAREN))
+ return;
+ skipCommentsUntil(T_RPAREN);
+ if (m_suites.isEmpty())
+ return;
+ m_suites.removeLast();
+}
+
+void BoostCodeParser::handleTestCase(TestCaseType testCaseType)
+{
+ if (!skipCommentsUntil(T_LPAREN))
+ return;
+
+ Token token;
+ BoostTestCodeLocationAndType locationAndType;
+
+ switch (testCaseType) {
+ case TestCaseType::Functions: // cannot have decorators passed as parameter
+ case TestCaseType::Parameter:
+ case TestCaseType::Data:
+ if (testCaseType != TestCaseType::Data) {
+ if (!skipCommentsUntil(T_AMPER)) {
+ // content without the leading lparen
+ const QByteArray content = contentUntil(T_RPAREN).mid(1);
+ const QList<QByteArray> parts = content.split(',');
+ if (parts.size() == 0)
+ return;
+ locationAndType = locationAndTypeFromToken(token, m_source, m_currentState, m_suites);
+
+ const QByteArray functionName = parts.first();
+ if (isBoostBindCall(functionName))
+ locationAndType.m_name = QString::fromUtf8(content).append(')');
+ else
+ locationAndType.m_name = QString::fromUtf8(functionName);
+ m_testCases.append(locationAndType);
+ m_currentState = BoostTestTreeItem::Enabled;
+ return;
+ }
+ if (testCaseType == TestCaseType::Parameter)
+ m_currentState |= BoostTestTreeItem::Parameterized;
+ } else if (m_currentState.testFlag(BoostTestTreeItem::Fixture)) {
+ // ignore first parameter (fixture) and first comma
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return;
+ if (!skipCommentsUntil(T_COMMA))
+ return;
+ }
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return;
+ token = m_tokens.at(m_currentIndex);
+ locationAndType = locationAndTypeFromToken(token, m_source, m_currentState, m_suites);
+ m_testCases.append(locationAndType);
+ m_currentState = BoostTestTreeItem::Enabled;
+ return;
+
+ case TestCaseType::Auto:
+ case TestCaseType::Fixture:
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return;
+ token = m_tokens.at(m_currentIndex);
+
+ if (testCaseType == TestCaseType::Fixture) { // skip fixture class parameter
+ m_currentState |= BoostTestTreeItem::Fixture;
+ if (!skipCommentsUntil(T_COMMA))
+ return;
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return;
+ }
+ break;
+ }
+
+ // check and handle decorators and add the found test case
+ if (!skipCommentsUntil(T_COMMA)) {
+ if (skipCommentsUntil(T_RPAREN)) {
+ locationAndType = locationAndTypeFromToken(token, m_source, m_currentState, m_suites);
+ m_testCases.append(locationAndType);
+ m_currentState = BoostTestTreeItem::Enabled;
+ }
+ } else {
+ if (!m_currentState.testFlag(BoostTestTreeItem::Templated))
+ handleDecorators();
+ locationAndType = locationAndTypeFromToken(token, m_source, m_currentState, m_suites);
+ m_testCases.append(locationAndType);
+ m_currentState = BoostTestTreeItem::Enabled;
+ }
+}
+
+void BoostCodeParser::handleDecorator()
+{
+ skipCommentsUntil(T_LPAREN);
+ m_currentState = BoostTestTreeItem::Enabled;
+ handleDecorators();
+}
+
+void BoostCodeParser::handleDecorators()
+{
+ if (!skipCommentsUntil(T_STAR))
+ return;
+ if (!skipCommentsUntil(T_IDENTIFIER))
+ return;
+
+ QByteArray decorator = contentUntil(T_LPAREN);
+ if (decorator.isEmpty())
+ return;
+
+ bool aliasedOrReal;
+ QString symbolName;
+ QByteArray simplifiedName;
+
+ if (!evalCurrentDecorator(decorator, &symbolName, &simplifiedName, &aliasedOrReal))
+ return;
+
+ if (symbolName == "decorator::disabled" || (aliasedOrReal && simplifiedName == "::disabled")) {
+ m_currentState.setFlag(BoostTestTreeItem::Disabled);
+ } else if (symbolName == "decorator::enabled"
+ || (aliasedOrReal && simplifiedName == "::enabled")) {
+ m_currentState.setFlag(BoostTestTreeItem::Disabled, false);
+ m_currentState.setFlag(BoostTestTreeItem::ExplicitlyEnabled);
+ } else if (symbolName == "decorator::enable_if"
+ || (aliasedOrReal && simplifiedName.startsWith("::enable_if<"))) {
+ // figure out the passed template value
+ QByteArray templateType = decorator.mid(decorator.indexOf('<') + 1);
+ templateType.chop(templateType.size() - templateType.indexOf('>'));
+
+ if (templateType == "true") {
+ m_currentState.setFlag(BoostTestTreeItem::Disabled, false);
+ m_currentState.setFlag(BoostTestTreeItem::ExplicitlyEnabled);
+ } else if (templateType == "false") {
+ m_currentState.setFlag(BoostTestTreeItem::Disabled);
+ } else {
+ // FIXME we have a const(expr) bool? currently not easily achievable
+ }
+ } else if (symbolName == "decorator::fixture"
+ || (aliasedOrReal && simplifiedName.startsWith("::fixture"))){
+ m_currentState.setFlag(BoostTestTreeItem::Fixture);
+ }
+ // TODO.. depends_on, label, precondition, timeout,...
+
+ skipCommentsUntil(T_LPAREN);
+ skipCommentsUntil(T_RPAREN);
+
+ handleDecorators(); // check for more decorators
+}
+
+bool BoostCodeParser::skipCommentsUntil(const Kind nextExpectedKind)
+{
+ for (int index = m_currentIndex + 1, end = m_tokens.size(); index < end; ++index) {
+ const Token &token = m_tokens.at(index);
+ if (token.isComment())
+ continue;
+ if (token.kind() != nextExpectedKind)
+ break;
+ m_currentIndex = index;
+ return true;
+ }
+ return false;
+}
+
+QByteArray BoostCodeParser::contentUntil(Kind stopKind)
+{
+ QByteArray result;
+ for (int oldIndex = m_currentIndex, end = m_tokens.size(); oldIndex < end; ++oldIndex) {
+ const Token &token = m_tokens.at(oldIndex);
+ if (token.isComment())
+ continue;
+ if (token.kind() == stopKind)
+ return result;
+ result.append(m_source.mid(int(token.bytesBegin()), int(token.bytes())));
+ }
+ return result;
+}
+
+bool BoostCodeParser::isBoostBindCall(const QByteArray &function)
+{
+ if (!function.contains("bind"))
+ return false;
+ int index = function.indexOf('(');
+ if (index == -1)
+ return false;
+ QByteArray funcCall = function.left(index);
+ const QList<LookupItem> lookupItems = m_typeOfExpression(funcCall, m_doc->globalNamespace());
+ if (lookupItems.isEmpty())
+ return false;
+
+ if (funcCall.contains("::")) {
+ bool aliasedOrReal = false;
+ aliasedOrRealNamespace(funcCall, "boost", nullptr, &aliasedOrReal);
+ return aliasedOrReal;
+ }
+
+ Overview overview;
+ for (const LookupItem &item : lookupItems) {
+ if (Symbol *symbol = item.declaration()) {
+ const QString fullQualified = overview.prettyName(
+ m_lookupContext.fullyQualifiedName(symbol->enclosingNamespace()));
+ if (fullQualified == "boost")
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BoostCodeParser::aliasedOrRealNamespace(const QByteArray &symbolName,
+ const QString &origNamespace,
+ QByteArray *simplifiedName, bool *aliasedOrReal)
+{
+ Overview overview;
+ const QByteArray classOrNamespace = symbolName.left(symbolName.lastIndexOf("::"));
+ const QList<LookupItem> lookup = m_typeOfExpression(classOrNamespace, m_doc->globalNamespace());
+ for (const LookupItem &it : lookup) {
+ if (auto classOrNamespaceSymbol = it.declaration()) {
+ const QString fullQualified = overview.prettyName(
+ m_lookupContext.fullyQualifiedName(classOrNamespaceSymbol));
+ if (fullQualified == origNamespace) {
+ *aliasedOrReal = true;
+ if (simplifiedName)
+ *simplifiedName = symbolName.mid(symbolName.lastIndexOf("::"));
+ return true;
+ }
+ if (auto namespaceAlias = classOrNamespaceSymbol->asNamespaceAlias()) {
+ if (auto aliasName = namespaceAlias->namespaceName()) {
+ if (overview.prettyName(aliasName) == origNamespace) {
+ *aliasedOrReal = true;
+ if (simplifiedName)
+ *simplifiedName = symbolName.mid(symbolName.lastIndexOf("::"));
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool BoostCodeParser::evalCurrentDecorator(const QByteArray &decorator, QString *symbolName,
+ QByteArray *simplifiedName, bool *aliasedOrReal)
+{
+ const QList<LookupItem> lookupItems = m_typeOfExpression(decorator, m_doc->globalNamespace());
+ if (lookupItems.isEmpty())
+ return false;
+
+ Overview overview;
+ Symbol *symbol = lookupItems.first().declaration();
+ if (!symbol->name())
+ return false;
+
+ *symbolName = overview.prettyName(symbol->name());
+ *aliasedOrReal = false;
+ if (decorator.contains("::"))
+ return aliasedOrRealNamespace(decorator, "boost::unit_test", simplifiedName, aliasedOrReal);
+ return true;
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boostcodeparser.h b/src/plugins/autotest/boost/boostcodeparser.h
new file mode 100644
index 0000000000..23fd4b3c03
--- /dev/null
+++ b/src/plugins/autotest/boost/boostcodeparser.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "boosttesttreeitem.h"
+
+#include <cplusplus/CppDocument.h>
+#include <cplusplus/LookupContext.h>
+#include <cplusplus/SimpleLexer.h>
+#include <cplusplus/TypeOfExpression.h>
+
+#include <QByteArray>
+
+namespace Autotest {
+namespace Internal {
+
+class BoostCodeParser
+{
+public:
+ BoostCodeParser(const QByteArray &source, const CPlusPlus::LanguageFeatures &features,
+ const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot);
+ virtual ~BoostCodeParser() = default;
+ BoostTestCodeLocationList findTests();
+private:
+ enum class TestCaseType {Auto, Functions, Parameter, Fixture, Data};
+
+ void handleIdentifier();
+ void handleSuiteBegin(bool isFixture);
+ void handleSuiteEnd();
+ void handleTestCase(TestCaseType testCaseType);
+ void handleDecorator();
+ void handleDecorators();
+
+ bool skipCommentsUntil(CPlusPlus::Kind nextExpectedKind); // moves currentIndex if succeeds
+ QByteArray contentUntil(CPlusPlus::Kind stopKind); // does not move currentIndex
+
+ bool isBoostBindCall(const QByteArray &function);
+ bool aliasedOrRealNamespace(const QByteArray &symbolName, const QString &origNamespace,
+ QByteArray *simplifiedName, bool *aliasedOrReal);
+ bool evalCurrentDecorator(const QByteArray &decorator, QString *symbolName,
+ QByteArray *simplifiedName, bool *aliasedOrReal);
+
+ const QByteArray &m_source;
+ const CPlusPlus::LanguageFeatures &m_features;
+ const CPlusPlus::Document::Ptr &m_doc;
+ const CPlusPlus::Snapshot &m_snapshot;
+ CPlusPlus::LookupContext m_lookupContext;
+ CPlusPlus::TypeOfExpression m_typeOfExpression;
+ CPlusPlus::Tokens m_tokens;
+ int m_currentIndex = 0;
+ BoostTestCodeLocationList m_testCases;
+ QVector<BoostTestInfo> m_suites;
+ QString m_currentSuite;
+ BoostTestTreeItem::TestStates m_currentState = BoostTestTreeItem::Enabled;
+ unsigned m_lineNo = 0;
+};
+
+} // Internal
+} // Autotest
diff --git a/src/plugins/autotest/boost/boosttestconfiguration.cpp b/src/plugins/autotest/boost/boosttestconfiguration.cpp
new file mode 100644
index 0000000000..276c83bc6d
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestconfiguration.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** 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 "boosttestconfiguration.h"
+#include "boosttestconstants.h"
+#include "boosttestoutputreader.h"
+#include "boosttestsettings.h"
+
+#include "../autotestplugin.h"
+#include "../testframeworkmanager.h"
+#include "../testsettings.h"
+
+namespace Autotest {
+namespace Internal {
+
+static QSharedPointer<BoostTestSettings> getBoostSettings()
+{
+ const Core::Id id = Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(
+ BoostTest::Constants::FRAMEWORK_NAME);
+ TestFrameworkManager *manager = TestFrameworkManager::instance();
+ return qSharedPointerCast<BoostTestSettings>(manager->settingsForTestFramework(id));
+}
+
+TestOutputReader *BoostTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
+ QProcess *app) const
+{
+ auto settings = getBoostSettings();
+ return new BoostTestOutputReader(fi, app, buildDirectory(), projectFile(),
+ settings->logLevel, settings->reportLevel);
+}
+
+enum class InterferingType { Options, EnvironmentVariables };
+
+static QStringList interfering(InterferingType type)
+{
+ const QStringList knownInterfering { "log_level", "log_format", "log_sink",
+ "report_level", "report_format", "report_sink",
+ "output_format", "color_output", "no_color_output",
+ "catch_system_errors", "no_catch_system_errors",
+ "detect_fp_exceptions", "no_detect_fp_exceptions",
+ "detect_memory_leaks", "random", "run_test",
+ "show_progress", "result_code", "no_result_code",
+ "help", "list_content", "list_labels", "version"
+ };
+ switch (type) {
+ case InterferingType::Options:
+ return Utils::transform(knownInterfering, [](const QString &item) {
+ return QString("--" + item);
+ });
+ case InterferingType::EnvironmentVariables:
+ return Utils::transform(knownInterfering, [](const QString &item) {
+ return QString("BOOST_TEST_" + item).toUpper();
+ });
+ }
+ return QStringList();
+}
+
+static QStringList filterInterfering(const QStringList &provided, QStringList *omitted)
+{
+ const QStringList knownInterfering = interfering(InterferingType::Options);
+ const QString interferingSingleWithParam = "efklortcpsx?";
+ QStringList allowed;
+ bool filterNextArg = false;
+ bool ignoreRest = false;
+ for (auto arg : provided) {
+ bool filterArg = filterNextArg;
+ filterNextArg = false;
+ if (ignoreRest) {
+ allowed.append(arg);
+ continue;
+ }
+ bool interferes = false;
+ if (filterArg && !arg.startsWith('-')) {
+ interferes = true;
+ } else if (arg.startsWith("--")) {
+ if (arg.size() == 2)
+ ignoreRest = true;
+ else
+ interferes = knownInterfering.contains(arg.left(arg.indexOf('=')));
+ } else if (arg.startsWith('-') && arg.size() > 1) {
+ interferes = interferingSingleWithParam.contains(arg.at(1));
+ filterNextArg = interferes;
+ }
+ if (!interferes)
+ allowed.append(arg);
+ else if (omitted)
+ omitted->append(arg);
+ }
+ return allowed;
+}
+
+QStringList BoostTestConfiguration::argumentsForTestRunner(QStringList *omitted) const
+{
+ auto boostSettings = getBoostSettings();
+ QStringList arguments;
+ arguments << "-l" << BoostTestSettings::logLevelToOption(boostSettings->logLevel);
+ arguments << "-r" << BoostTestSettings::reportLevelToOption(boostSettings->reportLevel);
+ arguments << "--no_color_output"; // ensure that colored output is not used as default
+
+ if (boostSettings->randomize)
+ arguments << QString("--random=").append(QString::number(boostSettings->seed));
+
+ if (boostSettings->systemErrors)
+ arguments << "-s";
+ if (boostSettings->fpExceptions)
+ arguments << "--detect_fp_exceptions";
+ if (!boostSettings->memLeaks)
+ arguments << "--detect_memory_leaks=0";
+
+ // TODO improve the test case gathering and arguments building to avoid too long command lines
+ for (const QString &test : testCases())
+ arguments << "-t" << test;
+
+ if (AutotestPlugin::settings()->processArgs) {
+ arguments << filterInterfering(runnable().commandLineArguments.split(
+ ' ', QString::SkipEmptyParts), omitted);
+ }
+ return arguments;
+}
+
+Utils::Environment BoostTestConfiguration::filteredEnvironment(const Utils::Environment &original) const
+{
+ const QStringList interferingEnv = interfering(InterferingType::EnvironmentVariables);
+
+ Utils::Environment result = original;
+ for (const QString &key : interferingEnv)
+ result.unset(key);
+ return result;
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestconfiguration.h b/src/plugins/autotest/boost/boosttestconfiguration.h
new file mode 100644
index 0000000000..e792fe21d5
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestconfiguration.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "../testconfiguration.h"
+
+namespace Autotest {
+namespace Internal {
+
+class BoostTestConfiguration : public DebuggableTestConfiguration
+{
+public:
+ BoostTestConfiguration() {}
+ TestOutputReader *outputReader(const QFutureInterface<TestResultPtr> &fi,
+ QProcess *app) const override;
+ QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override;
+ Utils::Environment filteredEnvironment(const Utils::Environment &original) const override;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestconstants.h b/src/plugins/autotest/boost/boosttestconstants.h
new file mode 100644
index 0000000000..2c993c1d4f
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestconstants.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtGlobal>
+
+namespace Autotest {
+namespace BoostTest {
+namespace Constants {
+
+const char FRAMEWORK_NAME[] = "Boost";
+const char FRAMEWORK_SETTINGS_CATEGORY[] = QT_TRANSLATE_NOOP("BoostTestFramework", "Boost Test");
+const unsigned FRAMEWORK_PRIORITY = 11;
+const char BOOST_MASTER_SUITE[] = "Master Test Suite";
+
+} // namespace Constants
+} // namespace BoostTest
+} // namespace AutoTest
diff --git a/src/plugins/autotest/boost/boosttestframework.cpp b/src/plugins/autotest/boost/boosttestframework.cpp
new file mode 100644
index 0000000000..a6b7515154
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestframework.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 "boosttestframework.h"
+#include "boosttestconstants.h"
+#include "boosttestsettings.h"
+#include "boosttestsettingspage.h"
+#include "boosttesttreeitem.h"
+#include "boosttestparser.h"
+#include "../testframeworkmanager.h"
+
+namespace Autotest {
+namespace Internal {
+
+ITestParser *BoostTestFramework::createTestParser() const
+{
+ return new BoostTestParser;
+}
+
+TestTreeItem *BoostTestFramework::createRootNode() const
+{
+ return new BoostTestTreeItem(
+ QCoreApplication::translate("BoostTestFramework",
+ BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY),
+ QString(), TestTreeItem::Root);
+}
+
+const char *BoostTestFramework::name() const
+{
+ return BoostTest::Constants::FRAMEWORK_NAME;
+}
+
+unsigned BoostTestFramework::priority() const
+{
+ return BoostTest::Constants::FRAMEWORK_PRIORITY;
+}
+
+IFrameworkSettings *BoostTestFramework::createFrameworkSettings() const
+{
+ return new BoostTestSettings;
+}
+
+ITestSettingsPage *BoostTestFramework::createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const
+{
+ return new BoostTestSettingsPage(settings, this);
+}
+
+bool BoostTestFramework::hasFrameworkSettings() const
+{
+ return true;
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestframework.h b/src/plugins/autotest/boost/boosttestframework.h
new file mode 100644
index 0000000000..c9db343deb
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestframework.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "../itestframework.h"
+
+namespace Autotest {
+namespace Internal {
+
+class BoostTestFramework : public ITestFramework
+{
+public:
+ BoostTestFramework() : ITestFramework(true) {}
+ const char *name() const override;
+ unsigned priority() const override;
+ IFrameworkSettings *createFrameworkSettings() const override;
+ ITestSettingsPage *createSettingsPage(QSharedPointer<IFrameworkSettings> settings) const override;
+ bool hasFrameworkSettings() const override;
+protected:
+ ITestParser *createTestParser() const override;
+ TestTreeItem *createRootNode() const override;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp
new file mode 100644
index 0000000000..3ae5756d3a
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp
@@ -0,0 +1,457 @@
+/****************************************************************************
+**
+** 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 "boosttestoutputreader.h"
+#include "boosttestsettings.h"
+#include "boosttestresult.h"
+
+#include <utils/qtcassert.h>
+
+#include <QDir>
+#include <QFileInfo>
+#include <QLoggingCategory>
+#include <QRegularExpression>
+
+namespace Autotest {
+namespace Internal {
+
+static Q_LOGGING_CATEGORY(orLog, "qtc.autotest.boost.outputreader", QtWarningMsg)
+
+static QString constructSourceFilePath(const QString &path, const QString &filePath)
+{
+ return QFileInfo(path, filePath).canonicalFilePath();
+}
+
+BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
+ QProcess *testApplication,
+ const QString &buildDirectory,
+ const QString &projectFile,
+ LogLevel log, ReportLevel report)
+ : TestOutputReader(futureInterface, testApplication, buildDirectory)
+ , m_projectFile(projectFile)
+ , m_logLevel(log)
+ , m_reportLevel(report)
+{
+ if (m_testApplication) {
+ connect(m_testApplication, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
+ this, &BoostTestOutputReader::onFinished);
+ }
+}
+
+// content of "error:..." / "info:..." / ... messages
+static QString caseFromContent(const QString &content)
+{
+ const int length = content.length();
+ if (content.startsWith("last checkpoint:")) {
+ int index = content.indexOf('"');
+ if (index != 17 || length <= 18) {
+ qCDebug(orLog) << "double quote position" << index << " or content length" << length
+ << "wrong on content" << content;
+ return QString();
+ }
+ index = content.indexOf('"', 18);
+ if (index == -1) {
+ qCDebug(orLog) << "no closing double quote" << content;
+ return QString();
+ }
+ return content.mid(18, index - 1);
+ }
+
+ int index = content.indexOf(": in ");
+ if (index == -1) // "info: check true has passed"
+ return QString();
+
+ if (index <= 4 || length < index + 4) {
+ qCDebug(orLog) << "unexpected position" << index << "for info" << content;
+ return QString();
+ }
+
+ QString result = content.mid(index + 5);
+ static QRegularExpression functionName("\"(.+)\":.*");
+ const QRegularExpressionMatch matcher = functionName.match(result);
+ if (!matcher.hasMatch()) {
+ qCDebug(orLog) << "got no match";
+ return QString();
+ }
+ return matcher.captured(1);
+}
+
+void BoostTestOutputReader::sendCompleteInformation()
+{
+ QTC_ASSERT(m_result != ResultType::Invalid, return);
+ BoostTestResult *result = new BoostTestResult(id(), m_projectFile, m_currentModule);
+ result->setTestSuite(m_currentSuite);
+ result->setTestCase(m_currentTest);
+ if (m_lineNumber) {
+ result->setLine(m_lineNumber);
+ result->setFileName(m_fileName);
+ }
+
+ result->setDescription(m_description);
+ result->setResult(m_result);
+ reportResult(TestResultPtr(result));
+ m_result = ResultType::Invalid;
+}
+
+void BoostTestOutputReader::handleMessageMatch(const QRegularExpressionMatch &match)
+{
+ m_fileName = constructSourceFilePath(m_buildDir, match.captured(1));
+ m_lineNumber = match.captured(2).toInt();
+
+ const QString &content = match.captured(3);
+ if (content.startsWith("info:")) {
+ if (m_currentTest.isEmpty() || m_logLevel > LogLevel::UnitScope) {
+ QString tmp = caseFromContent(content);
+ if (!tmp.isEmpty())
+ m_currentTest = tmp;
+ }
+ m_result = ResultType::Pass;
+ m_description = content;
+ } else if (content.startsWith("error:")) {
+ if (m_currentTest.isEmpty() || m_logLevel > LogLevel::UnitScope)
+ m_currentTest = caseFromContent(content);
+ m_result = ResultType::Fail;
+ if (m_reportLevel == ReportLevel::No)
+ ++m_summary[ResultType::Fail];
+ m_description = content;
+ } else if (content.startsWith("fatal error:")) {
+ if (m_currentTest.isEmpty() || m_logLevel > LogLevel::UnitScope)
+ m_currentTest = caseFromContent(content);
+ m_result = ResultType::MessageFatal;
+ m_description = content;
+ } else if (content.startsWith("last checkpoint:")) {
+ if (m_currentTest.isEmpty() || m_logLevel > LogLevel::UnitScope)
+ m_currentTest = caseFromContent(content);
+ m_result = ResultType::MessageInfo;
+ m_description = content;
+ } else if (content.startsWith("Entering")) {
+ m_result = ResultType::TestStart;
+ const QString type = match.captured(8);
+ if (type == "case") {
+ m_currentTest = match.captured(9);
+ m_description = tr("Executing test case %1").arg(m_currentTest);
+ } else if (type == "suite") {
+ m_currentSuite = match.captured(9);
+ m_description = tr("Executing test suite %1").arg(m_currentSuite);
+ }
+ } else if (content.startsWith("Leaving")) {
+ const QString type = match.captured(10);
+ if (type == "case") {
+ if (m_currentTest != match.captured(11) && m_currentTest.isEmpty())
+ m_currentTest = match.captured(11);
+ m_result = ResultType::TestEnd;
+ m_description = tr("Test execution took %1").arg(match.captured(12));
+ } else if (type == "suite") {
+ if (m_currentSuite != match.captured(11) && m_currentSuite.isEmpty())
+ m_currentSuite = match.captured(11);
+ m_currentTest.clear();
+ m_result = ResultType::TestEnd;
+ m_description = tr("Test suite execution took %1").arg(match.captured(12));
+ }
+ } else if (content.startsWith("Test case ")) {
+ m_currentTest = match.captured(4);
+ m_result = ResultType::Skip;
+ if (m_reportLevel == ReportLevel::Confirm || m_reportLevel == ReportLevel::No)
+ ++m_summary[ResultType::Skip];
+ m_description = content;
+ }
+
+ if (m_result != ResultType::Invalid) // we got a new result
+ sendCompleteInformation();
+}
+
+void BoostTestOutputReader::processOutputLine(const QByteArray &outputLineWithNewLine)
+{
+ static QRegularExpression newTestStart("^Running (\\d+) test cases?\\.\\.\\.$");
+ static QRegularExpression dependency("^Including test case (.+) as a dependency of "
+ "test case (.+)$");
+ static QRegularExpression messages("^(.+)\\((\\d+)\\): (info: (.+)|error: (.+)|"
+ "fatal error: (.+)|last checkpoint: (.+)"
+ "|Entering test (case|suite) \"(.+)\""
+ "|Leaving test (case|suite) \"(.+)\"; testing time: (\\d+.+)"
+ "|Test case \"(.+)\" is skipped because .+$)$");
+ static QRegularExpression moduleMssg("^(Entering test module \"(.+)\"|"
+ "Leaving test module \"(.+)\"; testing time: (\\d+.+))$");
+ static QRegularExpression noAssertion("^Test case (.*) did not check any assertions$");
+
+ static QRegularExpression summaryPreamble("^\\s*Test (module|suite|case) \"(.*)\" has "
+ "(failed|passed)( with:)?$");
+ static QRegularExpression summarySkip("^\\s+Test case \"(.*)\" was skipped$");
+ static QRegularExpression summaryDetail("^\\s+(\\d+) test cases? out of (\\d+) "
+ "(failed|passed|skipped)$");
+ static QRegularExpression summaryAssertion("^\\s+(\\d+) assertions? out of (\\d+) "
+ "(failed|passed)$");
+
+ static QRegularExpression finish("^\\*{3} (\\d+) failure(s are| is) detected in the "
+ "test module \"(.*)\"$");
+ static QRegularExpression errDetect("^\\*{3} Errors where detected in the "
+ "test module \"(.*}\"; see standard output for details");
+ QString noErrors("*** No errors detected");
+
+ const QString line = QString::fromUtf8(chopLineBreak(outputLineWithNewLine));
+ if (line.trimmed().isEmpty())
+ return;
+
+ QRegularExpressionMatch match = messages.match(line);
+ if (match.hasMatch()) {
+ handleMessageMatch(match);
+ return;
+ }
+
+ match = dependency.match(line);
+ if (match.hasMatch()) {
+ if (m_result != ResultType::Invalid)
+ sendCompleteInformation();
+ BoostTestResult *result = new BoostTestResult(id(), m_projectFile, m_currentModule);
+ result->setDescription(match.captured(0));
+ result->setResult(ResultType::MessageInfo);
+ reportResult(TestResultPtr(result));
+ return;
+ }
+
+ match = newTestStart.match(line);
+ if (match.hasMatch()) {
+ if (m_result != ResultType::Invalid)
+ sendCompleteInformation();
+ m_testCaseCount = match.captured(1).toInt();
+ m_description.clear();
+ return;
+ }
+
+ match = moduleMssg.match(line);
+ if (match.hasMatch()) {
+ if (m_result != ResultType::Invalid)
+ sendCompleteInformation();
+ if (match.captured(1).startsWith("Entering")) {
+ m_currentModule = match.captured(2);
+ BoostTestResult *result = new BoostTestResult(id(), m_projectFile, m_currentModule);
+ result->setDescription(tr("Executing test module %1").arg(m_currentModule));
+ result->setResult(ResultType::TestStart);
+ reportResult(TestResultPtr(result));
+ m_description.clear();
+ } else {
+ QTC_CHECK(m_currentModule == match.captured(3));
+ BoostTestResult *result = new BoostTestResult(id(), m_projectFile, m_currentModule);
+ result->setDescription(tr("Test module execution took %1").arg(match.captured(4)));
+ result->setResult(ResultType::TestEnd);
+ reportResult(TestResultPtr(result));
+
+ m_currentTest.clear();
+ m_currentSuite.clear();
+ m_currentModule.clear();
+ m_description.clear();
+ }
+ return;
+ }
+
+ match = noAssertion.match(line);
+ if (match.hasMatch()) {
+ if (m_result != ResultType::Invalid)
+ sendCompleteInformation();
+ const QString caseWithOptionalSuite = match.captured(1);
+ int index = caseWithOptionalSuite.lastIndexOf('/');
+ if (index == -1) {
+ QTC_CHECK(caseWithOptionalSuite == m_currentTest);
+ } else {
+ QTC_CHECK(caseWithOptionalSuite.mid(index + 1) == m_currentTest);
+ int sIndex = caseWithOptionalSuite.lastIndexOf('/', index - 1);
+ if (sIndex == -1) {
+ QTC_CHECK(caseWithOptionalSuite.left(index) == m_currentSuite);
+ m_currentSuite = caseWithOptionalSuite.left(index); // FIXME should not be necessary - but we currently do not care for the whole suite path
+ } else {
+ QTC_CHECK(caseWithOptionalSuite.mid(sIndex + 1, index - sIndex - 1) == m_currentSuite);
+ }
+ }
+ createAndReportResult(match.captured(0), ResultType::MessageWarn);
+ return;
+ }
+
+ match = summaryPreamble.match(line);
+ if (match.hasMatch()) {
+ createAndReportResult(match.captured(0), ResultType::MessageInfo);
+ if (m_reportLevel == ReportLevel::Detailed || match.captured(4).isEmpty()) {
+ if (match.captured(1) == "case") {
+ if (match.captured(3) == "passed")
+ ++m_summary[ResultType::Pass];
+ else
+ ++m_summary[ResultType::Fail];
+ }
+ }
+ return;
+ }
+
+ match = summaryDetail.match(line);
+ if (match.hasMatch()) {
+ createAndReportResult(match.captured(0), ResultType::MessageInfo);
+ int report = match.captured(1).toInt();
+ QString type = match.captured(3);
+ if (m_reportLevel != ReportLevel::Detailed) {
+ if (type == "passed")
+ m_summary[ResultType::Pass] += report;
+ else if (type == "failed")
+ m_summary[ResultType::Fail] += report;
+ else if (type == "skipped")
+ m_summary[ResultType::Skip] += report;
+ }
+
+ return;
+ }
+
+ match = summaryAssertion.match(line);
+ if (match.hasMatch()) {
+ createAndReportResult(match.captured(0), ResultType::MessageInfo);
+ return;
+ }
+
+ match = summarySkip.match(line);
+ if (match.hasMatch()) {
+ createAndReportResult(match.captured(0), ResultType::MessageInfo);
+ if (m_reportLevel == ReportLevel::Detailed)
+ ++m_summary[ResultType::Skip];
+ return;
+ }
+
+ match = finish.match(line);
+ if (match.hasMatch()) {
+ if (m_result != ResultType::Invalid)
+ sendCompleteInformation();
+ BoostTestResult *result = new BoostTestResult(id(), m_projectFile, QString());
+ int failed = match.captured(1).toInt();
+ QString txt = tr("%1 failures detected in %2.").arg(failed).arg(match.captured(3));
+ int passed = (m_testCaseCount != -1)
+ ? m_testCaseCount - failed - m_summary[ResultType::Skip] : -1;
+ if (m_testCaseCount != -1)
+ txt.append(' ').append(tr("%1 tests passed.").arg(passed));
+ result->setDescription(txt);
+ result->setResult(ResultType::MessageInfo);
+ reportResult(TestResultPtr(result));
+ if (m_reportLevel == ReportLevel::Confirm) { // for the final summary
+ m_summary[ResultType::Pass] += passed;
+ m_summary[ResultType::Fail] += failed;
+ }
+ m_testCaseCount = -1;
+ return;
+ }
+
+ if (line == noErrors) {
+ if (m_result != ResultType::Invalid)
+ sendCompleteInformation();
+ BoostTestResult *result = new BoostTestResult(id(), m_projectFile, QString());
+ QString txt = tr("No errors detected.");
+ if (m_testCaseCount != -1)
+ txt.append(' ').append(tr("%1 tests passed.").arg(m_testCaseCount));
+ result->setDescription(txt);
+ result->setResult(ResultType::MessageInfo);
+ reportResult(TestResultPtr(result));
+ if (m_reportLevel == ReportLevel::Confirm) // for the final summary
+ m_summary.insert(ResultType::Pass, m_testCaseCount);
+ return;
+ }
+
+ // some plain output...
+ if (!m_description.isEmpty())
+ m_description.append('\n');
+ m_description.append(line);
+}
+
+void BoostTestOutputReader::processStdError(const QByteArray &output)
+{
+ // we need to process the output, Boost UTF uses both out streams
+ int start = 0;
+ int index = -1;
+ while ((index = output.indexOf('\n', start)) != -1) {
+ const QByteArray &line = output.mid(start, index - start + 1);
+ if (!line.isEmpty()) {
+ if (line != QByteArray(1, '\n'))
+ processOutputLine(line);
+ emit newOutputAvailable(line);
+ }
+ start = index + 1;
+ }
+ if (start > 0) { // remove? this never happens
+ const QByteArray lastLine = output.mid(start) + '\n';
+ if (!lastLine.isEmpty()) {
+ if (lastLine != QByteArray(1, '\n'))
+ processOutputLine(lastLine);
+ emit newOutputAvailable(lastLine);
+ }
+ }
+}
+
+TestResultPtr BoostTestOutputReader::createDefaultResult() const
+{
+ BoostTestResult *result = new BoostTestResult(id(), m_projectFile, m_currentModule);
+ result->setTestSuite(m_currentSuite);
+ result->setTestCase(m_currentTest);
+
+ return TestResultPtr(result);
+}
+
+void BoostTestOutputReader::onFinished(int exitCode, QProcess::ExitStatus /*exitState*/) {
+ if (m_reportLevel == ReportLevel::No && m_testCaseCount != -1) {
+ int reportedFailsAndSkips = m_summary[ResultType::Fail] + m_summary[ResultType::Skip];
+ m_summary.insert(ResultType::Pass, m_testCaseCount - reportedFailsAndSkips);
+ }
+ // boost::exit_success (0), boost::exit_test_failure (201)
+ // or boost::exit_exception_failure (200)
+ // be graceful and do not add a fatal for exit_test_failure
+ if (m_logLevel == LogLevel::Nothing && m_reportLevel == ReportLevel::No) {
+ switch (exitCode) {
+ case 0:
+ reportNoOutputFinish(tr("Running tests exited with ") + "boost::exit_success.",
+ ResultType::Pass);
+ break;
+ case 200:
+ reportNoOutputFinish(
+ tr("Running tests exited with ") + "boost::exit_test_exception.",
+ ResultType::MessageFatal);
+ break;
+ case 201:
+ reportNoOutputFinish(tr("Running tests exited with ")
+ + "boost::exit_test_failure.", ResultType::Fail);
+ break;
+ }
+ } else if (exitCode != 0 && exitCode != 201 && !m_description.isEmpty()) {
+ if (m_description.startsWith("Test setup error:")) {
+ createAndReportResult(m_description + '\n' + tr("Executable: %1")
+ .arg(id()), ResultType::MessageWarn);
+ } else {
+ createAndReportResult(tr("Running tests failed.\n%1\nExecutable: %2")
+ .arg(m_description).arg(id()), ResultType::MessageFatal);
+ }
+ }
+}
+
+void BoostTestOutputReader::reportNoOutputFinish(const QString &description, ResultType type)
+{
+ BoostTestResult *result = new BoostTestResult(id(), m_projectFile, m_currentModule);
+ result->setTestCase(tr("Running tests without output."));
+ result->setDescription(description);
+ result->setResult(type);
+ reportResult(TestResultPtr(result));
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestoutputreader.h b/src/plugins/autotest/boost/boosttestoutputreader.h
new file mode 100644
index 0000000000..e16c1fb996
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestoutputreader.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "../testoutputreader.h"
+
+namespace Autotest {
+namespace Internal {
+
+class BoostTestResult;
+class TestTreeItem;
+enum class LogLevel;
+enum class ReportLevel;
+
+class BoostTestOutputReader : public TestOutputReader
+{
+public:
+ BoostTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
+ QProcess *testApplication, const QString &buildDirectory,
+ const QString &projectFile, LogLevel log, ReportLevel report);
+protected:
+ void processOutputLine(const QByteArray &outputLineWithNewLine) override;
+ void processStdError(const QByteArray &output) override;
+ TestResultPtr createDefaultResult() const override;
+
+private:
+ void onFinished(int exitCode, QProcess::ExitStatus /*exitState*/);
+ void sendCompleteInformation();
+ void handleMessageMatch(const QRegularExpressionMatch &match);
+ void reportNoOutputFinish(const QString &description, ResultType type);
+ QString m_projectFile;
+ QString m_currentModule;
+ QString m_currentSuite;
+ QString m_currentTest;
+ QString m_description;
+ QString m_fileName;
+ ResultType m_result = ResultType::Invalid;
+ int m_lineNumber = 0;
+ int m_testCaseCount = -1;
+ LogLevel m_logLevel;
+ ReportLevel m_reportLevel;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestparser.cpp b/src/plugins/autotest/boost/boosttestparser.cpp
new file mode 100644
index 0000000000..6f953e515a
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestparser.cpp
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** 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 "boosttestparser.h"
+#include "boostcodeparser.h"
+#include "boosttesttreeitem.h"
+
+#include <cpptools/cppmodelmanager.h>
+
+#include <QMap>
+#include <QRegularExpression>
+#include <QRegularExpressionMatch>
+
+namespace Autotest {
+namespace Internal {
+
+namespace BoostTestUtils {
+static const QStringList relevant = {
+ QStringLiteral("BOOST_AUTO_TEST_CASE"), QStringLiteral("BOOST_TEST_CASE"),
+ QStringLiteral("BOOST_DATA_TEST_CASE"), QStringLiteral("BOOST_FIXTURE_TEST_CASE"),
+ QStringLiteral("BOOST_PARAM_TEST_CASE"), QStringLiteral("BOOST_DATA_TEST_CASE_F"),
+ QStringLiteral("BOOST_AUTO_TEST_CASE_TEMPLATE"),
+ QStringLiteral("BOOST_FIXTURE_TEST_CASE_TEMPLATE"),
+};
+
+bool isBoostTestMacro(const QString &macro)
+{
+ return relevant.contains(macro);
+}
+} // BoostTestUtils
+
+TestTreeItem *BoostTestParseResult::createTestTreeItem() const
+{
+ if (itemType == TestTreeItem::Root)
+ return nullptr;
+
+ BoostTestTreeItem *item = new BoostTestTreeItem(displayName, fileName, itemType);
+ item->setProFile(proFile);
+ item->setLine(line);
+ item->setColumn(column);
+ item->setStates(state);
+ item->setFullName(name);
+
+ for (const TestParseResult *funcParseResult : children)
+ item->appendChild(funcParseResult->createTestTreeItem());
+ return item;
+}
+
+
+static bool includesBoostTest(const CPlusPlus::Document::Ptr &doc,
+ const CPlusPlus::Snapshot &snapshot)
+{
+ static const QRegularExpression boostTestHpp("^.*/boost/test/.*\\.hpp$");
+ for (const CPlusPlus::Document::Include &inc : doc->resolvedIncludes()) {
+ if (boostTestHpp.match(inc.resolvedFileName()).hasMatch())
+ return true;
+ }
+
+ for (const QString &include : snapshot.allIncludesForDocument(doc->fileName())) {
+ if (boostTestHpp.match(include).hasMatch())
+ return true;
+ }
+
+ return false;
+}
+
+static bool hasBoostTestMacros(const CPlusPlus::Document::Ptr &doc)
+{
+ for (const CPlusPlus::Document::MacroUse &macro : doc->macroUses()) {
+ if (!macro.isFunctionLike())
+ continue;
+ if (BoostTestUtils::isBoostTestMacro(QLatin1String(macro.macro().name())))
+ return true;
+ }
+ return false;
+}
+
+static BoostTestParseResult *createParseResult(const QString &name, const QString &filePath,
+ const QString &projectFile, const Core::Id &id,
+ TestTreeItem::Type type, const BoostTestInfo &info)
+{
+ BoostTestParseResult *partialSuite = new BoostTestParseResult(id);
+ partialSuite->itemType = type;
+ partialSuite->fileName = filePath;
+ partialSuite->name = info.fullName;
+ partialSuite->displayName = name;
+ partialSuite->line = info.line;
+ partialSuite->column = 0;
+ partialSuite->proFile = projectFile;
+ partialSuite->state = info.state;
+ return partialSuite;
+
+}
+
+static bool handleBoostTest(QFutureInterface<TestParseResultPtr> futureInterface,
+ const CPlusPlus::Document::Ptr &doc,
+ const CPlusPlus::Snapshot &snapshot,
+ const Core::Id &id)
+{
+ const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
+ const QString &filePath = doc->fileName();
+
+ const QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(filePath);
+ if (projectParts.isEmpty()) // happens if shutting down while parsing
+ return false;
+ const CppTools::ProjectPart::Ptr projectPart = projectParts.first();
+ const auto projectFile = projectPart->projectFile;
+ const QByteArray &fileContent = CppParser::getFileContent(filePath);
+
+ BoostCodeParser codeParser(fileContent, projectPart->languageFeatures, doc, snapshot);
+ const BoostTestCodeLocationList foundTests = codeParser.findTests();
+ if (foundTests.isEmpty())
+ return false;
+
+ for (const BoostTestCodeLocationAndType &locationAndType : foundTests) {
+ BoostTestInfoList suitesStates = locationAndType.m_suitesState;
+ BoostTestInfo firstSuite = suitesStates.first();
+ QStringList suites = firstSuite.fullName.split('/');
+ BoostTestParseResult *topLevelSuite = createParseResult(suites.first(), filePath,
+ projectFile, id,
+ TestTreeItem::TestSuite,
+ firstSuite);
+ BoostTestParseResult *currentSuite = topLevelSuite;
+ suitesStates.removeFirst();
+ while (suitesStates.size()) {
+ firstSuite = suitesStates.first();
+ suites = firstSuite.fullName.split('/');
+ BoostTestParseResult *suiteResult = createParseResult(suites.last(), filePath,
+ projectFile, id,
+ TestTreeItem::TestSuite,
+ firstSuite);
+ currentSuite->children.append(suiteResult);
+ suitesStates.removeFirst();
+ currentSuite = suiteResult;
+ }
+
+ if (currentSuite) {
+ BoostTestInfo tmpInfo{
+ locationAndType.m_suitesState.last().fullName + "::" + locationAndType.m_name,
+ locationAndType.m_state, locationAndType.m_line};
+ BoostTestParseResult *funcResult = createParseResult(locationAndType.m_name, filePath,
+ projectFile, id,
+ locationAndType.m_type,
+ tmpInfo);
+ currentSuite->children.append(funcResult);
+ futureInterface.reportResult(TestParseResultPtr(topLevelSuite));
+ }
+ }
+ return true;
+}
+
+bool BoostTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
+ const QString &fileName)
+{
+ CPlusPlus::Document::Ptr doc = document(fileName);
+ if (doc.isNull() || !includesBoostTest(doc, m_cppSnapshot) || !hasBoostTestMacros(doc))
+ return false;
+ return handleBoostTest(futureInterface, doc, m_cppSnapshot, id());
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestparser.h b/src/plugins/autotest/boost/boosttestparser.h
new file mode 100644
index 0000000000..678b859cc9
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestparser.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "../itestparser.h"
+#include "boosttesttreeitem.h"
+
+namespace Autotest {
+namespace Internal {
+
+class BoostTestParseResult : public TestParseResult
+{
+public:
+ explicit BoostTestParseResult(const Core::Id &id) : TestParseResult(id) {}
+ TestTreeItem *createTestTreeItem() const override;
+ // TODO special attributes/states (labeled, timeout,...?)
+ BoostTestTreeItem::TestStates state = BoostTestTreeItem::Enabled;
+};
+
+class BoostTestParser : public CppParser
+{
+public:
+ bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
+ const QString &fileName) override;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestresult.cpp b/src/plugins/autotest/boost/boosttestresult.cpp
new file mode 100644
index 0000000000..cf6d6e7b41
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestresult.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 "boosttestresult.h"
+
+namespace Autotest {
+namespace Internal {
+
+BoostTestResult::BoostTestResult(const QString &id, const QString &projectFile, const QString &name)
+ : TestResult(id, name), m_projectFile(projectFile)
+{
+}
+
+const QString BoostTestResult::outputString(bool selected) const
+{
+ const QString &desc = description();
+ QString output;
+ switch (result()) {
+ case ResultType::Pass:
+ case ResultType::Fail:
+ output = m_testCase;
+ if (selected && !desc.isEmpty())
+ output.append('\n').append(desc);
+ break;
+ default:
+ output = desc;
+ if (!selected)
+ output = output.split('\n').first();
+ }
+ return output;
+}
+
+bool BoostTestResult::isDirectParentOf(const TestResult *other, bool *needsIntermediate) const
+{
+ if (!TestResult::isDirectParentOf(other, needsIntermediate))
+ return false;
+
+ const BoostTestResult *boostOther = static_cast<const BoostTestResult *>(other);
+
+ if (m_testSuite != boostOther->m_testSuite)
+ return false;
+
+ if (result() == ResultType::TestStart) {
+ if (!boostOther->m_testCase.isEmpty())
+ return boostOther->m_testSuite == m_testSuite && boostOther->result() != ResultType::TestStart;
+
+ return boostOther->m_testCase == m_testCase;
+ }
+ return false;
+}
+
+} // namespace Internal
+} // namespace Autotest
+
diff --git a/src/plugins/autotest/boost/boosttestresult.h b/src/plugins/autotest/boost/boosttestresult.h
new file mode 100644
index 0000000000..b27dda16e8
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestresult.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "../testresult.h"
+
+namespace Autotest {
+namespace Internal {
+
+class BoostTestResult : public TestResult
+{
+public:
+ BoostTestResult(const QString &id, const QString &projectFile, const QString &name);
+ const QString outputString(bool selected) const override;
+
+ bool isDirectParentOf(const TestResult *other, bool *needsIntermediate) const override;
+ void setTestSuite(const QString &testSuite) { m_testSuite = testSuite; }
+ void setTestCase(const QString &testCase) { m_testCase = testCase; }
+private:
+ QString m_projectFile;
+ QString m_testSuite;
+ QString m_testCase;
+};
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestsettings.cpp b/src/plugins/autotest/boost/boosttestsettings.cpp
new file mode 100644
index 0000000000..7b1fc855ed
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestsettings.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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 "boosttestsettings.h"
+
+namespace Autotest {
+namespace Internal {
+
+static const char logLevelKey[] = "LogLevel";
+static const char reportLevelKey[] = "ReportLevel";
+static const char seedKey[] = "Seed";
+static const char randomizeKey[] = "Randomize";
+static const char systemErrorsKey[] = "SystemErrors";
+static const char fpExceptionsKey[] = "FPExceptions";
+static const char memLeaksKey[] = "MemoryLeaks";
+
+QString BoostTestSettings::name() const
+{
+ return QString("BoostTest");
+}
+
+void BoostTestSettings::fromFrameworkSettings(const QSettings *s)
+
+{
+ logLevel = LogLevel((s->value(logLevelKey, int(LogLevel::All)).toInt()));
+ reportLevel = ReportLevel((s->value(reportLevelKey, int(ReportLevel::Confirm)).toInt()));
+ systemErrors = s->value(systemErrorsKey, false).toBool();
+ fpExceptions = s->value(fpExceptionsKey, false).toBool();
+ memLeaks = s->value(memLeaksKey, true).toBool();
+ randomize = s->value(randomizeKey, false).toBool();
+ seed = s->value(seedKey, 0).toInt();
+}
+
+void BoostTestSettings::toFrameworkSettings(QSettings *s) const
+{
+ s->setValue(logLevelKey, int(logLevel));
+ s->setValue(reportLevelKey, int(reportLevel));
+ s->setValue(systemErrorsKey, systemErrors);
+ s->setValue(fpExceptionsKey, fpExceptions);
+ s->setValue(memLeaksKey, memLeaks);
+ s->setValue(randomizeKey, randomize);
+ s->setValue(seedKey, seed);
+}
+
+QString BoostTestSettings::logLevelToOption(const LogLevel logLevel)
+{
+ switch (logLevel) {
+ case LogLevel::All: return QString("all");
+ case LogLevel::Success: return QString("success");
+ case LogLevel::TestSuite: return QString("test_suite");
+ case LogLevel::UnitScope: return QString("unit_scope");
+ case LogLevel::Message: return QString("message");
+ case LogLevel::Error: return QString("error");
+ case LogLevel::CppException: return QString("cpp_exception");
+ case LogLevel::SystemError: return QString("system_error");
+ case LogLevel::FatalError: return QString("fatal_error");
+ case LogLevel::Nothing: return QString("nothing");
+ case LogLevel::Warning: return QString("warning");
+ }
+ return QString();
+}
+
+QString BoostTestSettings::reportLevelToOption(const ReportLevel reportLevel)
+{
+ switch (reportLevel) {
+ case ReportLevel::Confirm: return QString("confirm");
+ case ReportLevel::Short: return QString("short");
+ case ReportLevel::Detailed: return QString("detailed");
+ case ReportLevel::No: return QString("no");
+ }
+ return QString();
+}
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/boost/boosttestsettings.h b/src/plugins/autotest/boost/boosttestsettings.h
new file mode 100644
index 0000000000..8e10af856f
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestsettings.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "../iframeworksettings.h"
+
+namespace Autotest {
+namespace Internal {
+
+enum class LogLevel
+{
+ All,
+ Success,
+ TestSuite,
+ UnitScope,
+ Message,
+ Warning,
+ Error,
+ CppException,
+ SystemError,
+ FatalError,
+ Nothing
+};
+
+enum class ReportLevel
+{
+ Confirm,
+ Short,
+ Detailed,
+ No
+};
+
+class BoostTestSettings : public IFrameworkSettings
+{
+public:
+ BoostTestSettings() = default;
+ QString name() const override;
+ static QString logLevelToOption(const LogLevel logLevel);
+ static QString reportLevelToOption(const ReportLevel reportLevel);
+
+ LogLevel logLevel = LogLevel::Warning;
+ ReportLevel reportLevel = ReportLevel::Confirm;
+ int seed = 0;
+ bool randomize = false;
+ bool systemErrors = false;
+ bool fpExceptions = false;
+ bool memLeaks = true;
+
+protected:
+ void fromFrameworkSettings(const QSettings *s) override;
+ void toFrameworkSettings(QSettings *s) const override;
+};
+
+} // namespace Internal
+} // namespace Autotest
+
+Q_DECLARE_METATYPE(Autotest::Internal::LogLevel)
+Q_DECLARE_METATYPE(Autotest::Internal::ReportLevel)
diff --git a/src/plugins/autotest/boost/boosttestsettingspage.cpp b/src/plugins/autotest/boost/boosttestsettingspage.cpp
new file mode 100644
index 0000000000..99d13a51da
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestsettingspage.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** 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 "boosttestsettingspage.h"
+#include "boosttestconstants.h"
+#include "boosttestsettings.h"
+#include "../testframeworkmanager.h"
+
+#include <coreplugin/icore.h>
+
+namespace Autotest {
+namespace Internal {
+
+BoostTestSettingsWidget::BoostTestSettingsWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ m_ui.setupUi(this);
+ fillComboBoxes();
+ connect(m_ui.randomizeCB, &QCheckBox::toggled, m_ui.seedSB, &QSpinBox::setEnabled);
+}
+
+void BoostTestSettingsWidget::setSettings(const BoostTestSettings &settings)
+{
+ m_ui.logFormatCB->setCurrentIndex(int(settings.logLevel));
+ m_ui.reportLevelCB->setCurrentIndex(int(settings.reportLevel));
+ m_ui.randomizeCB->setChecked(settings.randomize);
+ m_ui.seedSB->setValue(settings.seed);
+ m_ui.systemErrorCB->setChecked(settings.systemErrors);
+ m_ui.fpExceptions->setChecked(settings.fpExceptions);
+ m_ui.memoryLeakCB->setChecked(settings.memLeaks);
+}
+
+BoostTestSettings BoostTestSettingsWidget::settings() const
+{
+ BoostTestSettings result;
+
+ result.logLevel = LogLevel(m_ui.logFormatCB->currentData().toInt());
+ result.reportLevel = ReportLevel(m_ui.reportLevelCB->currentData().toInt());
+ result.randomize = m_ui.randomizeCB->isChecked();
+ result.seed = m_ui.seedSB->value();
+ result.systemErrors = m_ui.systemErrorCB->isChecked();
+ result.fpExceptions = m_ui.fpExceptions->isChecked();
+ result.memLeaks = m_ui.memoryLeakCB->isChecked();
+ return result;
+}
+
+void BoostTestSettingsWidget::fillComboBoxes()
+{
+ m_ui.logFormatCB->addItem("All", QVariant::fromValue(LogLevel::All));
+ m_ui.logFormatCB->addItem("Success", QVariant::fromValue(LogLevel::Success));
+ m_ui.logFormatCB->addItem("Test Suite", QVariant::fromValue(LogLevel::TestSuite));
+ m_ui.logFormatCB->addItem("Unit Scope", QVariant::fromValue(LogLevel::UnitScope));
+ m_ui.logFormatCB->addItem("Message", QVariant::fromValue(LogLevel::Message));
+ m_ui.logFormatCB->addItem("Warning", QVariant::fromValue(LogLevel::Warning));
+ m_ui.logFormatCB->addItem("Error", QVariant::fromValue(LogLevel::Error));
+ m_ui.logFormatCB->addItem("C++ Exception", QVariant::fromValue(LogLevel::CppException));
+ m_ui.logFormatCB->addItem("System Error", QVariant::fromValue(LogLevel::SystemError));
+ m_ui.logFormatCB->addItem("Fatal Error", QVariant::fromValue(LogLevel::FatalError));
+ m_ui.logFormatCB->addItem("Nothing", QVariant::fromValue(LogLevel::Nothing));
+
+ m_ui.reportLevelCB->addItem("Confirm", QVariant::fromValue(ReportLevel::Confirm));
+ m_ui.reportLevelCB->addItem("Short", QVariant::fromValue(ReportLevel::Short));
+ m_ui.reportLevelCB->addItem("Detailed", QVariant::fromValue(ReportLevel::Detailed));
+ m_ui.reportLevelCB->addItem("No", QVariant::fromValue(ReportLevel::No));
+}
+
+BoostTestSettingsPage::BoostTestSettingsPage(QSharedPointer<IFrameworkSettings> settings,
+ const ITestFramework *framework)
+ : ITestSettingsPage(framework),
+ m_settings(qSharedPointerCast<BoostTestSettings>(settings))
+{
+ setDisplayName(QCoreApplication::translate("BoostTestFramework",
+ BoostTest::Constants::FRAMEWORK_SETTINGS_CATEGORY));
+}
+
+QWidget *BoostTestSettingsPage::widget()
+{
+ if (!m_widget) {
+ m_widget = new BoostTestSettingsWidget;
+ m_widget->setSettings(*m_settings);
+ }
+ return m_widget;
+}
+
+void BoostTestSettingsPage::apply()
+{
+ if (!m_widget) // page was not shown at all
+ return;
+
+ *m_settings = m_widget->settings();
+ m_settings->toSettings(Core::ICore::settings());
+}
+
+} // Internal
+} // Autotest
diff --git a/src/plugins/autotest/boost/boosttestsettingspage.h b/src/plugins/autotest/boost/boosttestsettingspage.h
new file mode 100644
index 0000000000..5e0e65f7b9
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestsettingspage.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "ui_boosttestsettingspage.h"
+#include "../itestsettingspage.h"
+
+#include <QPointer>
+
+namespace Autotest {
+namespace Internal {
+
+class IFrameworkSettings;
+class BoostTestSettings;
+
+class BoostTestSettingsWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit BoostTestSettingsWidget(QWidget *parent = nullptr);
+
+ void setSettings(const BoostTestSettings &settings);
+ BoostTestSettings settings() const;
+private:
+ void fillComboBoxes();
+ Ui::BoostSettingsPage m_ui;
+};
+
+class BoostTestSettingsPage : public ITestSettingsPage
+{
+ Q_OBJECT
+public:
+ BoostTestSettingsPage(QSharedPointer<IFrameworkSettings> settings,
+ const ITestFramework *framework);
+
+ QWidget *widget() override;
+ void apply() override;
+
+private:
+ QSharedPointer<BoostTestSettings> m_settings;
+ QPointer<BoostTestSettingsWidget> m_widget;
+};
+
+} // Internal
+} // Autotest
diff --git a/src/plugins/autotest/boost/boosttestsettingspage.ui b/src/plugins/autotest/boost/boosttestsettingspage.ui
new file mode 100644
index 0000000000..1596cd7d41
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttestsettingspage.ui
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BoostSettingsPage</class>
+ <widget class="QWidget" name="BoostSettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>309</width>
+ <height>284</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Log format:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="logFormatCB"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Report level:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="reportLevelCB"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="randomizeCB">
+ <property name="toolTip">
+ <string>Randomize execution order.</string>
+ </property>
+ <property name="text">
+ <string>Randomize</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Seed:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="seedSB">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>A seed of 0 means no randomization. A value of 1 uses the current time any other value is used as random seed generator.</string>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="systemErrorCB">
+ <property name="toolTip">
+ <string>Catch or ignore system errors.</string>
+ </property>
+ <property name="text">
+ <string>Catch system errors</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="fpExceptions">
+ <property name="toolTip">
+ <string>Enable floating point exception traps.</string>
+ </property>
+ <property name="text">
+ <string>Floating point exceptions</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="memoryLeakCB">
+ <property name="toolTip">
+ <string>Enable memory leak detection.</string>
+ </property>
+ <property name="text">
+ <string>Detect memory leaks</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>84</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/autotest/boost/boosttesttreeitem.cpp b/src/plugins/autotest/boost/boosttesttreeitem.cpp
new file mode 100644
index 0000000000..e2e58c28af
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttesttreeitem.cpp
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** 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"
+#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()
+{
+ BoostTestTreeItem *copied = new BoostTestTreeItem;
+ 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:
+ if (TestFrameworkManager::instance()->groupingEnabled(result->frameworkId)) {
+ 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());
+ return new BoostTestTreeItem(base.baseName(), fileInfo.absolutePath(), TestTreeItem::GroupNode);
+}
+
+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;
+}
+
+QList<TestConfiguration *> BoostTestTreeItem::getAllTestConfigurations() const
+{
+ QList<TestConfiguration *> result;
+ 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) {
+ BoostTestConfiguration *config = new BoostTestConfiguration;
+ config->setProject(project);
+ config->setProjectFile(it.key());
+ config->setTestCaseCount(it.value().testCases);
+ config->setInternalTargets(it.value().internalTargets);
+ result.append(config);
+ }
+ return result;
+}
+
+QList<TestConfiguration *> BoostTestTreeItem::getSelectedTestConfigurations() const
+{
+ QList<TestConfiguration *> result;
+ ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
+ if (!project || type() != Root)
+ return result;
+
+ struct BoostTestCases {
+ QStringList testCases;
+ QSet<QString> internalTargets;
+ };
+
+ QHash<QString, BoostTestCases> testCasesForProjectFile;
+ forAllChildren([&testCasesForProjectFile](TreeItem *it){
+ 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;
+ if (item->checked() == Qt::Checked) {
+ QString tcName = item->name();
+ if (item->state().testFlag(BoostTestTreeItem::Templated))
+ tcName.append("<*");
+ tcName = handleSpecialFunctionNames(tcName);
+ 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) {
+ BoostTestConfiguration *config = new BoostTestConfiguration;
+ config->setProject(project);
+ config->setProjectFile(it.key());
+ config->setTestCases(it.value().testCases);
+ config->setInternalTargets(it.value().internalTargets);
+ result.append(config);
+ }
+ return result;
+}
+
+TestConfiguration *BoostTestTreeItem::testConfiguration() const
+{
+ 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) {
+ forFirstLevelChildren([&testCases](TestTreeItem *child) {
+ 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("/*");
+ else if (boostItem->state().testFlag(BoostTestTreeItem::Templated))
+ tcName.append("<*");
+ testCases.append(boostItem->prependWithParentsSuitePaths(tcName));
+ }
+ }
+ });
+ } else {
+ QString tcName = name();
+ if (state().testFlag(BoostTestTreeItem::Templated))
+ tcName.append("<*");
+ testCases.append(prependWithParentsSuitePaths(handleSpecialFunctionNames(tcName)));
+ }
+
+ BoostTestConfiguration *config = new BoostTestConfiguration;
+ config->setProjectFile(proFile());
+ config->setProject(project);
+ config->setTestCases(testCases);
+ config->setInternalTargets(internalTargets());
+ return config;
+ }
+ return nullptr;
+}
+
+TestConfiguration *BoostTestTreeItem::debugConfiguration() const
+{
+ 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"),
+ QCoreApplication::translate("BoostTestTreeItem", "fixture"),
+ QCoreApplication::translate("BoostTestTreeItem", "templated")};
+ QString suffix;
+ if (m_state & Parameterized)
+ suffix = QString(" [") + markups[0];
+ if (m_state & Fixture)
+ suffix += (suffix.isEmpty() ? QString(" [") : QString(", ")) + markups[1];
+ if (m_state & Templated)
+ suffix += (suffix.isEmpty() ? QString(" [") : QString(", ")) + markups[2];
+ if (!suffix.isEmpty())
+ suffix += ']';
+ return suffix;
+}
+
+bool BoostTestTreeItem::enabled() const
+{
+ if (m_state & ExplicitlyEnabled)
+ return true;
+
+ if (m_state & Disabled)
+ return false;
+
+ 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
diff --git a/src/plugins/autotest/boost/boosttesttreeitem.h b/src/plugins/autotest/boost/boosttesttreeitem.h
new file mode 100644
index 0000000000..1149720f9d
--- /dev/null
+++ b/src/plugins/autotest/boost/boosttesttreeitem.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "../testtreeitem.h"
+
+namespace Autotest {
+namespace Internal {
+
+class BoostTestParseResult;
+
+class BoostTestTreeItem : public TestTreeItem
+{
+public:
+ enum TestState
+ {
+ Enabled = 0x00,
+ Disabled = 0x01,
+ ExplicitlyEnabled = 0x02,
+
+ Parameterized = 0x10,
+ Fixture = 0x20,
+ Templated = 0x40,
+ };
+ Q_FLAGS(TestState)
+ Q_DECLARE_FLAGS(TestStates, TestState)
+
+ explicit BoostTestTreeItem(const QString &name = QString(), const QString &filePath = QString(),
+ Type type = Root) : TestTreeItem(name, filePath, type) {}
+
+public:
+ TestTreeItem *copyWithoutChildren() override;
+ QVariant data(int column, int role) const override;
+ TestTreeItem *find(const TestParseResult *result) override;
+ TestTreeItem *findChild(const TestTreeItem *other) override;
+ bool modify(const TestParseResult *result) override;
+ TestTreeItem *createParentGroupNode() const override;
+
+ void setFullName(const QString &fullName) { m_fullName = fullName; }
+ QString fullName() const { return m_fullName; }
+ void setStates(TestStates states) { m_state = states; }
+ void setState(TestState state) { m_state |= state; }
+ TestStates state() const { return m_state; }
+
+ QList<TestConfiguration *> getAllTestConfigurations() const override;
+ QList<TestConfiguration *> getSelectedTestConfigurations() const override;
+ bool canProvideTestConfiguration() const override { return type() != Root; }
+ bool canProvideDebugConfiguration() const override { return canProvideTestConfiguration(); }
+ TestConfiguration *testConfiguration() const override;
+ TestConfiguration *debugConfiguration() const override;
+
+private:
+ QString nameSuffix() const;
+ bool enabled() const;
+ TestTreeItem *findChildByNameStateAndFile(const QString &name,
+ BoostTestTreeItem::TestStates state,
+ const QString &proFile) const;
+ QString prependWithParentsSuitePaths(const QString &testName) const;
+ bool modifyTestContent(const BoostTestParseResult *result);
+ TestStates m_state = Enabled;
+ QString m_fullName;
+};
+
+struct BoostTestInfo
+{
+ QString fullName; // formatted like UNIX path
+ BoostTestTreeItem::TestStates state;
+ unsigned line;
+};
+
+typedef QVector<BoostTestInfo> BoostTestInfoList;
+
+class BoostTestCodeLocationAndType : public TestCodeLocationAndType
+{
+public:
+ BoostTestTreeItem::TestStates m_state;
+ BoostTestInfoList m_suitesState;
+};
+
+typedef QVector<BoostTestCodeLocationAndType> BoostTestCodeLocationList;
+
+
+} // namespace Internal
+} // namespace Autotest
diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp
index d66ab7700b..f64155ed42 100644
--- a/src/plugins/autotest/gtest/gtestoutputreader.cpp
+++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp
@@ -31,7 +31,7 @@
#include <QDir>
#include <QFileInfo>
-#include <QRegExp>
+#include <QRegularExpression>
namespace Autotest {
namespace Internal {
@@ -48,12 +48,11 @@ GTestOutputReader::GTestOutputReader(const QFutureInterface<TestResultPtr> &futu
, m_projectFile(projectFile)
{
if (m_testApplication) {
- connect(m_testApplication,
- static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
+ connect(m_testApplication, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, [this] (int exitCode, QProcess::ExitStatus /*exitStatus*/) {
if (exitCode == 1 && !m_description.isEmpty()) {
createAndReportResult(tr("Running tests failed.\n %1\nExecutable: %2")
- .arg(m_description).arg(id()), Result::MessageFatal);
+ .arg(m_description).arg(id()), ResultType::MessageFatal);
}
// on Windows abort() will result in normal termination, but exit code will be set to 3
if (Utils::HostOsInfo::isWindowsHost() && exitCode == 3)
@@ -64,106 +63,108 @@ GTestOutputReader::GTestOutputReader(const QFutureInterface<TestResultPtr> &futu
void GTestOutputReader::processOutputLine(const QByteArray &outputLineWithNewLine)
{
- static QRegExp newTestStarts("^\\[-{10}\\] \\d+ tests? from (.*)$");
- static QRegExp testEnds("^\\[-{10}\\] \\d+ tests? from (.*) \\((.*)\\)$");
- static QRegExp newTestSetStarts("^\\[ RUN \\] (.*)$");
- static QRegExp testSetSuccess("^\\[ OK \\] (.*) \\((.*)\\)$");
- static QRegExp testSetFail("^\\[ FAILED \\] (.*) \\((\\d+ ms)\\)$");
- static QRegExp disabledTests("^ YOU HAVE (\\d+) DISABLED TESTS?$");
- static QRegExp failureLocation("^(.*):(\\d+): Failure$");
- static QRegExp errorLocation("^(.*)\\((\\d+)\\): error:.*$");
- static QRegExp iterations("^Repeating all tests \\(iteration (\\d+)\\) \\. \\. \\.$");
+ static const QRegularExpression newTestStarts("^\\[-{10}\\] \\d+ tests? from (.*)$");
+ static const QRegularExpression testEnds("^\\[-{10}\\] \\d+ tests? from (.*) \\((.*)\\)$");
+ static const QRegularExpression newTestSetStarts("^\\[ RUN \\] (.*)$");
+ static const QRegularExpression testSetSuccess("^\\[ OK \\] (.*) \\((.*)\\)$");
+ static const QRegularExpression testSetFail("^\\[ FAILED \\] (.*) \\((\\d+ ms)\\)$");
+ static const QRegularExpression disabledTests("^ YOU HAVE (\\d+) DISABLED TESTS?$");
+ static const QRegularExpression failureLocation("^(.*):(\\d+): Failure$");
+ static const QRegularExpression errorLocation("^(.*)\\((\\d+)\\): error:.*$");
+ static const QRegularExpression iterations("^Repeating all tests "
+ "\\(iteration (\\d+)\\) \\. \\. \\.$");
const QString line = QString::fromLatin1(chopLineBreak(outputLineWithNewLine));
if (line.trimmed().isEmpty())
return;
+ struct ExactMatch : public QRegularExpressionMatch
+ {
+ ExactMatch(const QRegularExpressionMatch &other) : QRegularExpressionMatch(other) {}
+ operator bool() const { return hasMatch(); }
+ };
+
if (!line.startsWith('[')) {
m_description.append(line).append('\n');
- if (iterations.exactMatch(line)) {
- m_iteration = iterations.cap(1).toInt();
+ if (ExactMatch match = iterations.match(line)) {
+ m_iteration = match.captured(1).toInt();
m_description.clear();
} else if (line.startsWith(QStringLiteral("Note:"))) {
m_description = line;
if (m_iteration > 1)
m_description.append(' ' + tr("(iteration %1)").arg(m_iteration));
TestResultPtr testResult = TestResultPtr(new GTestResult(id(), m_projectFile, QString()));
- testResult->setResult(Result::MessageInternal);
+ testResult->setResult(ResultType::MessageInternal);
testResult->setDescription(m_description);
reportResult(testResult);
m_description.clear();
- } else if (disabledTests.exactMatch(line)) {
- TestResultPtr testResult = TestResultPtr(new GTestResult(id(), m_projectFile, QString()));
- testResult->setResult(Result::MessageDisabledTests);
- int disabled = disabledTests.cap(1).toInt();
- testResult->setDescription(tr("You have %n disabled test(s).", nullptr, disabled));
- testResult->setLine(disabled); // misuse line property to hold number of disabled
- reportResult(testResult);
+ } else if (ExactMatch match = disabledTests.match(line)) {
+ m_disabled = match.captured(1).toInt();
m_description.clear();
}
return;
}
- if (testEnds.exactMatch(line)) {
+ if (ExactMatch match = testEnds.match(line)) {
TestResultPtr testResult = createDefaultResult();
- testResult->setResult(Result::MessageTestCaseEnd);
- testResult->setDescription(tr("Test execution took %1").arg(testEnds.cap(2)));
+ testResult->setResult(ResultType::TestEnd);
+ testResult->setDescription(tr("Test execution took %1").arg(match.captured(2)));
reportResult(testResult);
- m_currentTestName.clear();
- m_currentTestSet.clear();
- } else if (newTestStarts.exactMatch(line)) {
- setCurrentTestName(newTestStarts.cap(1));
+ m_currentTestSuite.clear();
+ m_currentTestCase.clear();
+ } else if (ExactMatch match = newTestStarts.match(line)) {
+ setCurrentTestSuite(match.captured(1));
TestResultPtr testResult = createDefaultResult();
- testResult->setResult(Result::MessageTestCaseStart);
+ testResult->setResult(ResultType::TestStart);
if (m_iteration > 1) {
- testResult->setDescription(tr("Repeating test case %1 (iteration %2)")
- .arg(m_currentTestName).arg(m_iteration));
+ testResult->setDescription(tr("Repeating test suite %1 (iteration %2)")
+ .arg(m_currentTestSuite).arg(m_iteration));
} else {
- testResult->setDescription(tr("Executing test case %1").arg(m_currentTestName));
+ testResult->setDescription(tr("Executing test suite %1").arg(m_currentTestSuite));
}
reportResult(testResult);
- } else if (newTestSetStarts.exactMatch(line)) {
- setCurrentTestSet(newTestSetStarts.cap(1));
- TestResultPtr testResult = TestResultPtr(new GTestResult(m_projectFile));
- testResult->setResult(Result::MessageCurrentTest);
- testResult->setDescription(tr("Entering test set %1").arg(m_currentTestSet));
+ } else if (ExactMatch match = newTestSetStarts.match(line)) {
+ setCurrentTestCase(match.captured(1));
+ TestResultPtr testResult = TestResultPtr(new GTestResult(QString(), m_projectFile,
+ QString()));
+ testResult->setResult(ResultType::MessageCurrentTest);
+ testResult->setDescription(tr("Entering test case %1").arg(m_currentTestCase));
reportResult(testResult);
m_description.clear();
- } else if (testSetSuccess.exactMatch(line)) {
+ } else if (ExactMatch match = testSetSuccess.match(line)) {
TestResultPtr testResult = createDefaultResult();
- testResult->setResult(Result::Pass);
+ testResult->setResult(ResultType::Pass);
testResult->setDescription(m_description);
reportResult(testResult);
m_description.clear();
testResult = createDefaultResult();
- testResult->setResult(Result::MessageInternal);
- testResult->setDescription(tr("Execution took %1.").arg(testSetSuccess.cap(2)));
+ testResult->setResult(ResultType::MessageInternal);
+ testResult->setDescription(tr("Execution took %1.").arg(match.captured(2)));
reportResult(testResult);
m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1);
- } else if (testSetFail.exactMatch(line)) {
+ } else if (ExactMatch match = testSetFail.match(line)) {
TestResultPtr testResult = createDefaultResult();
- testResult->setResult(Result::Fail);
+ testResult->setResult(ResultType::Fail);
m_description.chop(1);
QStringList resultDescription;
for (const QString &output : m_description.split('\n')) {
- QRegExp *match = nullptr;
- if (failureLocation.exactMatch(output))
- match = &failureLocation;
- else if (errorLocation.exactMatch(output))
- match = &errorLocation;
- if (!match) {
- resultDescription << output;
- continue;
+ QRegularExpressionMatch innerMatch = failureLocation.match(output);
+ if (!innerMatch.hasMatch()) {
+ innerMatch = errorLocation.match(output);
+ if (!innerMatch.hasMatch()) {
+ resultDescription << output;
+ continue;
+ }
}
testResult->setDescription(resultDescription.join('\n'));
reportResult(testResult);
resultDescription.clear();
testResult = createDefaultResult();
- testResult->setResult(Result::MessageLocation);
- testResult->setLine(match->cap(2).toInt());
- QString file = constructSourceFilePath(m_buildDir, match->cap(1));
+ testResult->setResult(ResultType::MessageLocation);
+ testResult->setLine(innerMatch.captured(2).toInt());
+ QString file = constructSourceFilePath(m_buildDir, innerMatch.captured(1));
if (!file.isEmpty())
testResult->setFileName(file);
resultDescription << output;
@@ -172,8 +173,8 @@ void GTestOutputReader::processOutputLine(const QByteArray &outputLineWithNewLin
reportResult(testResult);
m_description.clear();
testResult = createDefaultResult();
- testResult->setResult(Result::MessageInternal);
- testResult->setDescription(tr("Execution took %1.").arg(testSetFail.cap(2)));
+ testResult->setResult(ResultType::MessageInternal);
+ testResult->setDescription(tr("Execution took %1.").arg(match.captured(2)));
reportResult(testResult);
m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1);
}
@@ -181,8 +182,8 @@ void GTestOutputReader::processOutputLine(const QByteArray &outputLineWithNewLin
TestResultPtr GTestOutputReader::createDefaultResult() const
{
- GTestResult *result = new GTestResult(id(), m_projectFile, m_currentTestName);
- result->setTestSetName(m_currentTestSet);
+ GTestResult *result = new GTestResult(id(), m_projectFile, m_currentTestSuite);
+ result->setTestCaseName(m_currentTestCase);
result->setIteration(m_iteration);
const TestTreeItem *testItem = result->findTestTreeItem();
@@ -195,14 +196,14 @@ TestResultPtr GTestOutputReader::createDefaultResult() const
return TestResultPtr(result);
}
-void GTestOutputReader::setCurrentTestSet(const QString &testSet)
+void GTestOutputReader::setCurrentTestCase(const QString &testCase)
{
- m_currentTestSet = testSet;
+ m_currentTestCase = testCase;
}
-void GTestOutputReader::setCurrentTestName(const QString &testName)
+void GTestOutputReader::setCurrentTestSuite(const QString &testSuite)
{
- m_currentTestName = testName;
+ m_currentTestSuite = testSuite;
}
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestoutputreader.h b/src/plugins/autotest/gtest/gtestoutputreader.h
index 8f29ae73e1..6684b77f44 100644
--- a/src/plugins/autotest/gtest/gtestoutputreader.h
+++ b/src/plugins/autotest/gtest/gtestoutputreader.h
@@ -48,12 +48,12 @@ protected:
TestResultPtr createDefaultResult() const override;
private:
- void setCurrentTestSet(const QString &testSet);
- void setCurrentTestName(const QString &testName);
+ void setCurrentTestCase(const QString &testCase);
+ void setCurrentTestSuite(const QString &testSuite);
QString m_projectFile;
- QString m_currentTestName;
- QString m_currentTestSet;
+ QString m_currentTestSuite;
+ QString m_currentTestCase;
QString m_description;
int m_iteration = 1;
};
diff --git a/src/plugins/autotest/gtest/gtestparser.cpp b/src/plugins/autotest/gtest/gtestparser.cpp
index b21f161f06..f57f774ec0 100644
--- a/src/plugins/autotest/gtest/gtestparser.cpp
+++ b/src/plugins/autotest/gtest/gtestparser.cpp
@@ -36,7 +36,7 @@ namespace Internal {
TestTreeItem *GTestParseResult::createTestTreeItem() const
{
- if (itemType != TestTreeItem::TestCase && itemType != TestTreeItem::TestFunctionOrSet)
+ if (itemType != TestTreeItem::TestSuite && itemType != TestTreeItem::TestCase)
return nullptr;
GTestTreeItem *item = new GTestTreeItem(name, fileName, itemType);
item->setProFile(proFile);
@@ -110,7 +110,7 @@ static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
for (const GTestCaseSpec &testSpec : result.keys()) {
GTestParseResult *parseResult = new GTestParseResult(id);
- parseResult->itemType = TestTreeItem::TestCase;
+ parseResult->itemType = TestTreeItem::TestSuite;
parseResult->fileName = filePath;
parseResult->name = testSpec.testCaseName;
parseResult->parameterized = testSpec.parameterized;
@@ -139,12 +139,10 @@ static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
bool GTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName)
{
- if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
+ CPlusPlus::Document::Ptr doc = document(fileName);
+ if (doc.isNull() || !includesGTest(doc, m_cppSnapshot) || !hasGTestNames(doc))
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, id());
+ return handleGTest(futureInterface, doc, m_cppSnapshot, id());
}
} // namespace Internal
diff --git a/src/plugins/autotest/gtest/gtestresult.cpp b/src/plugins/autotest/gtest/gtestresult.cpp
index 645f1af0a8..b2f3aae67b 100644
--- a/src/plugins/autotest/gtest/gtestresult.cpp
+++ b/src/plugins/autotest/gtest/gtestresult.cpp
@@ -30,14 +30,11 @@
#include <coreplugin/id.h>
+#include <QRegularExpression>
+
namespace Autotest {
namespace Internal {
-GTestResult::GTestResult(const QString &projectFile, const QString &name)
- : TestResult(name), m_projectFile(projectFile)
-{
-}
-
GTestResult::GTestResult(const QString &id, const QString &projectFile,
const QString &name)
: TestResult(id, name), m_projectFile(projectFile)
@@ -49,9 +46,9 @@ const QString GTestResult::outputString(bool selected) const
const QString &desc = description();
QString output;
switch (result()) {
- case Result::Pass:
- case Result::Fail:
- output = m_testSetName;
+ case ResultType::Pass:
+ case ResultType::Fail:
+ output = m_testCaseName;
if (selected && !desc.isEmpty())
output.append('\n').append(desc);
break;
@@ -68,22 +65,20 @@ bool GTestResult::isDirectParentOf(const TestResult *other, bool *needsIntermedi
if (!TestResult::isDirectParentOf(other, needsIntermediate))
return false;
- if (result() == Result::MessageDisabledTests)
- return false;
const GTestResult *gtOther = static_cast<const GTestResult *>(other);
- if (m_testSetName == gtOther->m_testSetName) {
- const Result::Type otherResult = other->result();
- if (otherResult == Result::MessageInternal || otherResult == Result::MessageLocation)
- return result() != Result::MessageInternal && result() != Result::MessageLocation;
+ if (m_testCaseName == gtOther->m_testCaseName) {
+ const ResultType otherResult = other->result();
+ if (otherResult == ResultType::MessageInternal || otherResult == ResultType::MessageLocation)
+ return result() != ResultType::MessageInternal && result() != ResultType::MessageLocation;
}
if (m_iteration != gtOther->m_iteration)
return false;
- return isTest() && gtOther->isTestSet();
+ return isTestSuite() && gtOther->isTestCase();
}
static QString normalizeName(const QString &name)
{
- static QRegExp parameterIndex("/\\d+");
+ static QRegularExpression parameterIndex("/\\d+");
QString nameWithoutParameterIndices = name;
nameWithoutParameterIndices.remove(parameterIndex);
@@ -117,24 +112,24 @@ bool GTestResult::matches(const TestTreeItem *treeItem) const
if (treeItem->proFile() != m_projectFile)
return false;
- if (isTest())
- return matchesTestCase(treeItem);
+ if (isTestSuite())
+ return matchesTestSuite(treeItem);
- return matchesTestFunctionOrSet(treeItem);
+ return matchesTestCase(treeItem);
}
-bool GTestResult::matchesTestFunctionOrSet(const TestTreeItem *treeItem) const
+bool GTestResult::matchesTestCase(const TestTreeItem *treeItem) const
{
- if (treeItem->type() != TestTreeItem::TestFunctionOrSet)
+ if (treeItem->type() != TestTreeItem::TestCase)
return false;
- const QString testItemTestSet = treeItem->parentItem()->name() + '.' + treeItem->name();
- return testItemTestSet == normalizeName(m_testSetName);
+ const QString testItemTestCase = treeItem->parentItem()->name() + '.' + treeItem->name();
+ return testItemTestCase == normalizeName(m_testCaseName);
}
-bool GTestResult::matchesTestCase(const TestTreeItem *treeItem) const
+bool GTestResult::matchesTestSuite(const TestTreeItem *treeItem) const
{
- if (treeItem->type() != TestTreeItem::TestCase)
+ if (treeItem->type() != TestTreeItem::TestSuite)
return false;
return treeItem->name() == normalizeTestName(name());
diff --git a/src/plugins/autotest/gtest/gtestresult.h b/src/plugins/autotest/gtest/gtestresult.h
index 9e2d2557d8..a792213327 100644
--- a/src/plugins/autotest/gtest/gtestresult.h
+++ b/src/plugins/autotest/gtest/gtestresult.h
@@ -33,24 +33,23 @@ namespace Internal {
class GTestResult : public TestResult
{
public:
- explicit GTestResult(const QString &projectFile, const QString &name = QString());
GTestResult(const QString &id, const QString &projectFile, const QString &name);
const QString outputString(bool selected) const override;
- void setTestSetName(const QString &testSetName) { m_testSetName = testSetName; }
+ void setTestCaseName(const QString &testSetName) { m_testCaseName = testSetName; }
void setIteration(int iteration) { m_iteration = iteration; }
bool isDirectParentOf(const TestResult *other, bool *needsIntermediate) const override;
virtual const TestTreeItem *findTestTreeItem() const override;
private:
- bool isTest() const { return m_testSetName.isEmpty(); }
- bool isTestSet() const { return !m_testSetName.isEmpty(); }
+ bool isTestSuite() const { return m_testCaseName.isEmpty(); }
+ bool isTestCase() const { return !m_testCaseName.isEmpty(); }
bool matches(const TestTreeItem *item) const;
- bool matchesTestFunctionOrSet(const TestTreeItem *treeItem) const;
bool matchesTestCase(const TestTreeItem *treeItem) const;
+ bool matchesTestSuite(const TestTreeItem *treeItem) const;
- QString m_testSetName;
+ QString m_testCaseName;
QString m_projectFile;
int m_iteration = 1;
};
diff --git a/src/plugins/autotest/gtest/gtesttreeitem.cpp b/src/plugins/autotest/gtest/gtesttreeitem.cpp
index 335979131a..c344669b3c 100644
--- a/src/plugins/autotest/gtest/gtesttreeitem.cpp
+++ b/src/plugins/autotest/gtest/gtesttreeitem.cpp
@@ -37,7 +37,7 @@
#include <utils/qtcassert.h>
#include <utils/theme/theme.h>
-#include <QRegExp>
+#include <QRegularExpression>
namespace Autotest {
namespace Internal {
@@ -71,6 +71,20 @@ TestTreeItem *GTestTreeItem::copyWithoutChildren()
return copied;
}
+static QString wildCardPattern(const QString &original)
+{
+ QString pattern = original;
+ pattern.replace('.', "\\.");
+ pattern.replace('$', "\\$");
+ pattern.replace('(', "\\(").replace(')', "\\)");
+ pattern.replace('[', "\\[").replace(']', "\\]");
+ pattern.replace('{', "\\{").replace('}', "\\}");
+ pattern.replace('+', "\\+");
+ pattern.replace('*', ".*");
+ pattern.replace('?', '.');
+ return pattern;
+}
+
static bool matchesFilter(const QString &filter, const QString &fullTestName)
{
QStringList positive;
@@ -88,13 +102,13 @@ static bool matchesFilter(const QString &filter, const QString &fullTestName)
testName.append('.');
for (const QString &curr : negative) {
- QRegExp regex(curr, Qt::CaseSensitive, QRegExp::Wildcard);
- if (regex.exactMatch(testName))
+ QRegularExpression regex(wildCardPattern(curr));
+ if (regex.match(testName).hasMatch())
return false;
}
for (const QString &curr : positive) {
- QRegExp regex(curr, Qt::CaseSensitive, QRegExp::Wildcard);
- if (regex.exactMatch(testName))
+ QRegularExpression regex(wildCardPattern(curr));
+ if (regex.match(testName).hasMatch())
return true;
}
return positive.isEmpty();
@@ -130,8 +144,8 @@ QVariant GTestTreeItem::data(int column, int role) const
switch (type()) {
case Root:
case GroupNode:
+ case TestSuite:
case TestCase:
- case TestFunctionOrSet:
return checked();
default:
return QVariant();
@@ -153,7 +167,7 @@ TestConfiguration *GTestTreeItem::testConfiguration() const
GTestConfiguration *config = nullptr;
switch (type()) {
- case TestCase: {
+ case TestSuite: {
const QString &testSpecifier = gtestFilter(state()).arg(name()).arg('*');
if (int count = childCount()) {
config = new GTestConfiguration;
@@ -164,7 +178,7 @@ TestConfiguration *GTestTreeItem::testConfiguration() const
}
break;
}
- case TestFunctionOrSet: {
+ case TestCase: {
GTestTreeItem *parent = static_cast<GTestTreeItem *>(parentItem());
if (!parent)
return nullptr;
@@ -191,7 +205,7 @@ TestConfiguration *GTestTreeItem::debugConfiguration() const
return config;
}
-struct TestCases
+struct GTestCases
{
QStringList filters;
int testSetCount = 0;
@@ -199,7 +213,7 @@ struct TestCases
};
static void collectTestInfo(const GTestTreeItem *item,
- QHash<QString, TestCases> &testCasesForProFile,
+ QHash<QString, GTestCases> &testCasesForProFile,
bool ignoreCheckState)
{
QTC_ASSERT(item, return);
@@ -212,7 +226,7 @@ static void collectTestInfo(const GTestTreeItem *item,
}
const int childCount = item->childCount();
QTC_ASSERT(childCount != 0, return);
- QTC_ASSERT(item->type() == TestTreeItem::TestCase, return);
+ QTC_ASSERT(item->type() == TestTreeItem::TestSuite, return);
if (ignoreCheckState || item->checked() == Qt::Checked) {
const QString &projectFile = item->childAt(0)->proFile();
testCasesForProFile[projectFile].filters.append(
@@ -221,7 +235,7 @@ static void collectTestInfo(const GTestTreeItem *item,
testCasesForProFile[projectFile].internalTargets.unite(item->internalTargets());
} else if (item->checked() == Qt::PartiallyChecked) {
item->forFirstLevelChildren([&testCasesForProFile, item](TestTreeItem *child){
- QTC_ASSERT(child->type() == TestTreeItem::TestFunctionOrSet, return);
+ QTC_ASSERT(child->type() == TestTreeItem::TestCase, return);
if (child->checked() == Qt::Checked) {
testCasesForProFile[child->proFile()].filters.append(
gtestFilter(item->state()).arg(item->name()).arg(child->name()));
@@ -239,7 +253,7 @@ QList<TestConfiguration *> GTestTreeItem::getTestConfigurations(bool ignoreCheck
if (!project || type() != Root)
return result;
- QHash<QString, TestCases> testCasesForProFile;
+ QHash<QString, GTestCases> testCasesForProFile;
for (int row = 0, count = childCount(); row < count; ++row) {
auto child = static_cast<const GTestTreeItem *>(childAt(row));
collectTestInfo(child, testCasesForProFile, ignoreCheckState);
@@ -271,21 +285,21 @@ QList<TestConfiguration *> GTestTreeItem::getSelectedTestConfigurations() const
return getTestConfigurations(false);
}
-QList<TestConfiguration *> GTestTreeItem::getTestConfigurationsForFile(const Utils::FileName &fileName) const
+QList<TestConfiguration *> GTestTreeItem::getTestConfigurationsForFile(const Utils::FilePath &fileName) const
{
QList<TestConfiguration *> result;
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
if (!project || type() != Root)
return result;
- QHash<QString, TestCases> testCases;
+ QHash<QString, GTestCases> testCases;
const QString &file = fileName.toString();
forAllChildren([&testCases, &file](TestTreeItem *node) {
- if (node->type() == Type::TestFunctionOrSet && node->filePath() == file) {
+ if (node->type() == Type::TestCase && node->filePath() == file) {
QTC_ASSERT(node->parentItem(), return);
const GTestTreeItem *testCase = static_cast<GTestTreeItem *>(node->parentItem());
- QTC_ASSERT(testCase->type() == Type::TestCase, return);
- TestCases &cases = testCases[testCase->proFile()];
+ QTC_ASSERT(testCase->type() == Type::TestSuite, return);
+ GTestCases &cases = testCases[testCase->proFile()];
cases.filters.append(
gtestFilter(testCase->state()).arg(testCase->name(), node->name()));
cases.internalTargets.unite(node->internalTargets());
@@ -351,7 +365,7 @@ TestTreeItem *GTestTreeItem::find(const TestParseResult *result)
return findChildByNameStateAndFile(parseResult->name, states, parseResult->proFile);
case GroupNode:
return findChildByNameStateAndFile(parseResult->name, states, parseResult->proFile);
- case TestCase:
+ case TestSuite:
return findChildByNameAndFile(result->name, result->fileName);
default:
return nullptr;
@@ -367,7 +381,7 @@ TestTreeItem *GTestTreeItem::findChild(const TestTreeItem *other)
TestTreeItem *result = nullptr;
if (otherType == GroupNode) {
result = findChildByNameAndFile(other->name(), other->filePath());
- } else if (otherType == TestCase) {
+ } else if (otherType == TestSuite) {
auto gtOther = static_cast<const GTestTreeItem *>(other);
result = findChildByNameStateAndFile(gtOther->name(), gtOther->state(),
gtOther->proFile());
@@ -376,12 +390,12 @@ TestTreeItem *GTestTreeItem::findChild(const TestTreeItem *other)
}
case GroupNode: {
auto gtOther = static_cast<const GTestTreeItem *>(other);
- return otherType == TestCase
+ return otherType == TestSuite
? findChildByNameStateAndFile(gtOther->name(), gtOther->state(), gtOther->proFile())
: nullptr;
}
- case TestCase:
- return otherType == TestFunctionOrSet
+ case TestSuite:
+ return otherType == TestCase
? findChildByNameAndFile(other->name(), other->filePath())
: nullptr;
default:
@@ -394,7 +408,7 @@ bool GTestTreeItem::modify(const TestParseResult *result)
QTC_ASSERT(result, return false);
switch (type()) {
- case TestFunctionOrSet:
+ case TestCase:
return modifyTestSetContent(static_cast<const GTestParseResult *>(result));
default:
return false;
@@ -489,11 +503,11 @@ bool GTestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
return QFileInfo(other->filePath()).absolutePath() == filePath();
} else { // GTestFilter
QString fullName;
- if (other->type() == TestCase) {
+ if (other->type() == TestSuite) {
fullName = other->name();
if (other->childCount())
fullName += '.' + other->childAt(0)->name();
- } else if (other->type() == TestFunctionOrSet) {
+ } else if (other->type() == TestCase) {
QTC_ASSERT(other->parentItem(), return false);
fullName = other->parentItem()->name() + '.' + other->name();
} else if (other->type() == GroupNode) { // can happen on a rebuild if only filter changes
@@ -511,12 +525,12 @@ bool GTestTreeItem::isGroupNodeFor(const TestTreeItem *other) const
bool GTestTreeItem::isGroupable() const
{
- return type() == TestCase;
+ return type() == TestSuite;
}
TestTreeItem *GTestTreeItem::applyFilters()
{
- if (type() != TestCase)
+ if (type() != TestSuite)
return nullptr;
if (GTestFramework::groupMode() != GTest::Constants::GTestFilter)
@@ -540,5 +554,10 @@ TestTreeItem *GTestTreeItem::applyFilters()
return filtered;
}
+bool GTestTreeItem::shouldBeAddedAfterFiltering() const
+{
+ return type() == TestTreeItem::TestCase || childCount();
+}
+
} // namespace Internal
} // namespace Autotest
diff --git a/src/plugins/autotest/gtest/gtesttreeitem.h b/src/plugins/autotest/gtest/gtesttreeitem.h
index 8f1300007f..3b93116ffc 100644
--- a/src/plugins/autotest/gtest/gtesttreeitem.h
+++ b/src/plugins/autotest/gtest/gtesttreeitem.h
@@ -57,7 +57,7 @@ public:
TestConfiguration *debugConfiguration() const override;
QList<TestConfiguration *> getAllTestConfigurations() const override;
QList<TestConfiguration *> getSelectedTestConfigurations() const override;
- QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FileName &fileName) const override;
+ QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FilePath &fileName) const override;
TestTreeItem *find(const TestParseResult *result) override;
TestTreeItem *findChild(const TestTreeItem *other) override;
bool modify(const TestParseResult *result) override;
@@ -74,6 +74,7 @@ public:
bool isGroupNodeFor(const TestTreeItem *other) const override;
bool isGroupable() const override;
TestTreeItem *applyFilters() override;
+ bool shouldBeAddedAfterFiltering() const override;
private:
bool modifyTestSetContent(const GTestParseResult *result);
QList<TestConfiguration *> getTestConfigurations(bool ignoreCheckState) const;
diff --git a/src/plugins/autotest/gtest/gtestvisitors.cpp b/src/plugins/autotest/gtest/gtestvisitors.cpp
index 2cb8a70c31..f7104ff93d 100644
--- a/src/plugins/autotest/gtest/gtestvisitors.cpp
+++ b/src/plugins/autotest/gtest/gtestvisitors.cpp
@@ -78,7 +78,7 @@ bool GTestVisitor::visit(CPlusPlus::FunctionDefinitionAST *ast)
locationAndType.m_name = testName;
locationAndType.m_line = line;
locationAndType.m_column = column - 1;
- locationAndType.m_type = TestTreeItem::TestFunctionOrSet;
+ locationAndType.m_type = TestTreeItem::TestCase;
locationAndType.m_state = disabled ? GTestTreeItem::Disabled
: GTestTreeItem::Enabled;
GTestCaseSpec spec;
diff --git a/src/plugins/autotest/images/data@2x.png b/src/plugins/autotest/images/data@2x.png
new file mode 100644
index 0000000000..26f71a9ad0
--- /dev/null
+++ b/src/plugins/autotest/images/data@2x.png
Binary files differ
diff --git a/src/plugins/autotest/images/sort.png b/src/plugins/autotest/images/sort.png
deleted file mode 100644
index c15eb56d50..0000000000
--- a/src/plugins/autotest/images/sort.png
+++ /dev/null
Binary files differ
diff --git a/src/plugins/autotest/images/sort@2x.png b/src/plugins/autotest/images/sort@2x.png
deleted file mode 100644
index 1a2e5d9520..0000000000
--- a/src/plugins/autotest/images/sort@2x.png
+++ /dev/null
Binary files differ
diff --git a/src/plugins/autotest/images/suite.png b/src/plugins/autotest/images/suite.png
new file mode 100644
index 0000000000..91fc50bf32
--- /dev/null
+++ b/src/plugins/autotest/images/suite.png
Binary files differ
diff --git a/src/plugins/autotest/images/suite@2x.png b/src/plugins/autotest/images/suite@2x.png
new file mode 100644
index 0000000000..958480af60
--- /dev/null
+++ b/src/plugins/autotest/images/suite@2x.png
Binary files differ
diff --git a/src/plugins/autotest/itestparser.cpp b/src/plugins/autotest/itestparser.cpp
index 9d06320322..b7e1f15245 100644
--- a/src/plugins/autotest/itestparser.cpp
+++ b/src/plugins/autotest/itestparser.cpp
@@ -78,5 +78,10 @@ void CppParser::release()
m_workingCopy = CppTools::WorkingCopy();
}
+CPlusPlus::Document::Ptr CppParser::document(const QString &fileName)
+{
+ return selectedForBuilding(fileName) ? m_cppSnapshot.document(fileName) : nullptr;
+}
+
} // namespace Internal
} // namespace Autotest
diff --git a/src/plugins/autotest/itestparser.h b/src/plugins/autotest/itestparser.h
index b79b3c131b..b69b23b253 100644
--- a/src/plugins/autotest/itestparser.h
+++ b/src/plugins/autotest/itestparser.h
@@ -81,6 +81,8 @@ public:
static QByteArray getFileContent(const QString &filePath);
void release() override;
+ CPlusPlus::Document::Ptr document(const QString &fileName);
+
protected:
CPlusPlus::Snapshot m_cppSnapshot;
CppTools::WorkingCopy m_workingCopy;
diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp
index a74c24dccd..d71fd65509 100644
--- a/src/plugins/autotest/qtest/qttestoutputreader.cpp
+++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp
@@ -34,6 +34,8 @@
#include <QFileInfo>
#include <QRegularExpression>
+#include <cctype>
+
namespace Autotest {
namespace Internal {
@@ -188,6 +190,15 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
if (m_className.isEmpty() && outputLine.trimmed().isEmpty())
return;
+ if (m_expectTag) {
+ for (auto ch : outputLine) {
+ if (std::isspace(ch))
+ continue;
+ if (ch != '<')
+ return;
+ break;
+ }
+ }
m_xmlReader.addData(QString::fromUtf8(outputLine));
while (!m_xmlReader.atEnd()) {
if (m_futureInterface.isCanceled())
@@ -221,7 +232,7 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
m_description.clear();
m_duration.clear();
m_file.clear();
- m_result = Result::Invalid;
+ m_result = ResultType::Invalid;
m_lineNumber = 0;
const QXmlStreamAttributes &attributes = m_xmlReader.attributes();
m_result = TestResult::resultFromString(
@@ -237,24 +248,25 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
const int iterations = attributes.value(QStringLiteral("iterations")).toInt();
m_dataTag = attributes.value(QStringLiteral("tag")).toString();
m_description = constructBenchmarkInformation(metric, value, iterations);
- m_result = Result::Benchmark;
+ m_result = ResultType::Benchmark;
} else if (currentTag == QStringLiteral("DataTag")) {
m_cdataMode = DataTag;
} else if (currentTag == QStringLiteral("Description")) {
m_cdataMode = Description;
} else if (currentTag == QStringLiteral("QtVersion")) {
- m_result = Result::MessageInternal;
+ m_result = ResultType::MessageInternal;
m_cdataMode = QtVersion;
} else if (currentTag == QStringLiteral("QtBuild")) {
- m_result = Result::MessageInternal;
+ m_result = ResultType::MessageInternal;
m_cdataMode = QtBuild;
} else if (currentTag == QStringLiteral("QTestVersion")) {
- m_result = Result::MessageInternal;
+ m_result = ResultType::MessageInternal;
m_cdataMode = QTestVersion;
}
break;
}
case QXmlStreamReader::Characters: {
+ m_expectTag = false;
QStringRef text = m_xmlReader.text().trimmed();
if (text.isEmpty())
break;
@@ -285,6 +297,7 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
break;
}
case QXmlStreamReader::EndElement: {
+ m_expectTag = true;
m_cdataMode = None;
const QStringRef currentTag = m_xmlReader.name();
if (currentTag == QStringLiteral("TestFunction")) {
@@ -308,7 +321,7 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
&& m_xmlReader.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
createAndReportResult(tr("XML parsing failed.")
+ QString(" (%1) ").arg(m_xmlReader.error())
- + m_xmlReader.errorString(), Result::MessageFatal);
+ + m_xmlReader.errorString(), ResultType::MessageFatal);
}
break;
}
@@ -317,7 +330,7 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
static QStringList extractFunctionInformation(const QString &testClassName,
const QString &lineWithoutResultType,
- Result::Type resultType)
+ ResultType resultType)
{
static QRegularExpression classInformation("^(.+?)\\((.*?)\\)(.*)$");
QStringList result;
@@ -327,7 +340,7 @@ static QStringList extractFunctionInformation(const QString &testClassName,
QTC_ASSERT(fullQualifiedFunc.startsWith(testClassName + "::"), return result);
fullQualifiedFunc = fullQualifiedFunc.mid(testClassName.length() + 2);
result.append(fullQualifiedFunc);
- if (resultType == Result::Benchmark) { // tag is displayed differently
+ if (resultType == ResultType::Benchmark) { // tag is displayed differently
QString possiblyTag = match.captured(3);
if (!possiblyTag.isEmpty())
possiblyTag = possiblyTag.mid(2, possiblyTag.length() - 4);
@@ -452,7 +465,7 @@ void QtTestOutputReader::processSummaryFinishOutput()
sendFinishMessage(false);
m_className.clear();
m_description.clear();
- m_result = Result::Invalid;
+ m_result = ResultType::Invalid;
m_file.clear();
m_lineNumber = 0;
}
@@ -478,16 +491,16 @@ void QtTestOutputReader::sendCompleteInformation()
void QtTestOutputReader::sendMessageCurrentTest()
{
- TestResultPtr testResult = TestResultPtr(new QtTestResult(m_projectFile, m_testType));
- testResult->setResult(Result::MessageCurrentTest);
+ QtTestResult *testResult = new QtTestResult(QString(), m_projectFile, m_testType, QString());
+ testResult->setResult(ResultType::MessageCurrentTest);
testResult->setDescription(tr("Entering test function %1::%2").arg(m_className, m_testCase));
- reportResult(testResult);
+ reportResult(TestResultPtr(testResult));
}
void QtTestOutputReader::sendStartMessage(bool isFunction)
{
TestResultPtr testResult = createDefaultResult();
- testResult->setResult(Result::MessageTestCaseStart);
+ testResult->setResult(ResultType::TestStart);
testResult->setDescription(isFunction ? tr("Executing test function %1").arg(m_testCase)
: tr("Executing test case %1").arg(m_className));
const TestTreeItem *testItem = testResult->findTestTreeItem();
@@ -501,7 +514,7 @@ void QtTestOutputReader::sendStartMessage(bool isFunction)
void QtTestOutputReader::sendFinishMessage(bool isFunction)
{
TestResultPtr testResult = createDefaultResult();
- testResult->setResult(Result::MessageTestCaseEnd);
+ testResult->setResult(ResultType::TestEnd);
if (!m_duration.isEmpty()) {
testResult->setDescription(isFunction ? tr("Execution took %1 ms.").arg(m_duration)
: tr("Test execution took %1 ms.").arg(m_duration));
@@ -515,15 +528,15 @@ void QtTestOutputReader::sendFinishMessage(bool isFunction)
void QtTestOutputReader::handleAndSendConfigMessage(const QRegularExpressionMatch &config)
{
TestResultPtr testResult = createDefaultResult();
- testResult->setResult(Result::MessageInternal);
+ testResult->setResult(ResultType::MessageInternal);
testResult->setDescription(trQtVersion(config.captured(3)));
reportResult(testResult);
testResult = createDefaultResult();
- testResult->setResult(Result::MessageInternal);
+ testResult->setResult(ResultType::MessageInternal);
testResult->setDescription(trQtBuild(config.captured(2)));
reportResult(testResult);
testResult = createDefaultResult();
- testResult->setResult(Result::MessageInternal);
+ testResult->setResult(ResultType::MessageInternal);
testResult->setDescription(trQtestVersion(config.captured(1)));
reportResult(testResult);
}
diff --git a/src/plugins/autotest/qtest/qttestoutputreader.h b/src/plugins/autotest/qtest/qttestoutputreader.h
index a95a51a662..ce2b35416c 100644
--- a/src/plugins/autotest/qtest/qttestoutputreader.h
+++ b/src/plugins/autotest/qtest/qttestoutputreader.h
@@ -83,7 +83,7 @@ private:
QString m_testCase;
QString m_formerTestCase;
QString m_dataTag;
- Result::Type m_result = Result::Invalid;
+ ResultType m_result = ResultType::Invalid;
QString m_description;
QString m_file;
int m_lineNumber = 0;
@@ -91,7 +91,7 @@ private:
QXmlStreamReader m_xmlReader;
OutputMode m_mode = XML;
TestType m_testType = TestType::QtTest;
-
+ bool m_expectTag = true;
};
} // namespace Internal
diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp
index 234aeca79f..ddedf4dc52 100644
--- a/src/plugins/autotest/qtest/qttestparser.cpp
+++ b/src/plugins/autotest/qtest/qttestparser.cpp
@@ -389,9 +389,9 @@ void QtTestParser::release()
bool QtTestParser::processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
const QString &fileName)
{
- if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
+ CPlusPlus::Document::Ptr doc = document(fileName);
+ if (doc.isNull())
return false;
- CPlusPlus::Document::Ptr doc = m_cppSnapshot.find(fileName).value();
const QString &oldName = m_testCaseNames.value(fileName);
const QStringList &alternativeFiles = m_alternativeFiles.values(fileName);
if ((!includesQtTest(doc, m_cppSnapshot) || !qtTestLibDefined(fileName)) && oldName.isEmpty())
diff --git a/src/plugins/autotest/qtest/qttestresult.cpp b/src/plugins/autotest/qtest/qttestresult.cpp
index 5cb7fd0402..3e85c36e68 100644
--- a/src/plugins/autotest/qtest/qttestresult.cpp
+++ b/src/plugins/autotest/qtest/qttestresult.cpp
@@ -34,11 +34,6 @@
namespace Autotest {
namespace Internal {
-QtTestResult::QtTestResult(const QString &projectFile, TestType type, const QString &className)
- : TestResult(className), m_projectFile(projectFile), m_type(type)
-{
-}
-
QtTestResult::QtTestResult(const QString &id, const QString &projectFile, TestType type,
const QString &className)
: TestResult(id, className), m_projectFile(projectFile), m_type(type)
@@ -51,12 +46,12 @@ const QString QtTestResult::outputString(bool selected) const
const QString &className = name();
QString output;
switch (result()) {
- case Result::Pass:
- case Result::Fail:
- case Result::ExpectedFail:
- case Result::UnexpectedPass:
- case Result::BlacklistedFail:
- case Result::BlacklistedPass:
+ case ResultType::Pass:
+ case ResultType::Fail:
+ case ResultType::ExpectedFail:
+ case ResultType::UnexpectedPass:
+ case ResultType::BlacklistedFail:
+ case ResultType::BlacklistedPass:
output = className + "::" + m_function;
if (!m_dataTag.isEmpty())
output.append(QString(" (%1)").arg(m_dataTag));
@@ -64,7 +59,7 @@ const QString QtTestResult::outputString(bool selected) const
output.append('\n').append(desc);
}
break;
- case Result::Benchmark:
+ case ResultType::Benchmark:
output = className + "::" + m_function;
if (!m_dataTag.isEmpty())
output.append(QString(" (%1)").arg(m_dataTag));
@@ -89,12 +84,12 @@ bool QtTestResult::isDirectParentOf(const TestResult *other, bool *needsIntermed
return false;
const QtTestResult *qtOther = static_cast<const QtTestResult *>(other);
- if (TestResult::isMessageCaseStart(result())) {
+ if (result() == ResultType::TestStart) {
if (qtOther->isDataTag()) {
if (qtOther->m_function == m_function) {
if (m_dataTag.isEmpty()) {
// avoid adding function's TestCaseEnd to the data tag
- *needsIntermediate = qtOther->result() != Result::MessageTestCaseEnd;
+ *needsIntermediate = qtOther->result() != ResultType::TestEnd;
return true;
}
return qtOther->m_dataTag == m_dataTag;
@@ -164,7 +159,7 @@ bool QtTestResult::matches(const TestTreeItem *item) const
if (item->proFile() != m_projectFile)
return false;
return matchesTestCase(item);
- case TestTreeItem::TestFunctionOrSet:
+ case TestTreeItem::TestFunction:
case TestTreeItem::TestSpecialFunction:
if (!isTestFunction())
return false;
diff --git a/src/plugins/autotest/qtest/qttestresult.h b/src/plugins/autotest/qtest/qttestresult.h
index a0735a90c7..f3f653cd1a 100644
--- a/src/plugins/autotest/qtest/qttestresult.h
+++ b/src/plugins/autotest/qtest/qttestresult.h
@@ -34,7 +34,6 @@ namespace Internal {
class QtTestResult : public TestResult
{
public:
- QtTestResult(const QString &projectFile, TestType type, const QString &className = QString());
QtTestResult(const QString &id, const QString &projectFile, TestType type,
const QString &className);
const QString outputString(bool selected) const override;
diff --git a/src/plugins/autotest/qtest/qttesttreeitem.cpp b/src/plugins/autotest/qtest/qttesttreeitem.cpp
index 3fe96b6f39..7069e29961 100644
--- a/src/plugins/autotest/qtest/qttesttreeitem.cpp
+++ b/src/plugins/autotest/qtest/qttesttreeitem.cpp
@@ -82,7 +82,7 @@ Qt::ItemFlags QtTestTreeItem::flags(int column) const
switch (type()) {
case TestDataTag:
return defaultFlags | Qt::ItemIsUserCheckable;
- case TestFunctionOrSet:
+ case TestFunction:
return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
default:
return TestTreeItem::flags(column);
@@ -93,7 +93,7 @@ bool QtTestTreeItem::canProvideTestConfiguration() const
{
switch (type()) {
case TestCase:
- case TestFunctionOrSet:
+ case TestFunction:
case TestDataTag:
return true;
default:
@@ -119,7 +119,7 @@ TestConfiguration *QtTestTreeItem::testConfiguration() const
config->setProjectFile(proFile());
config->setProject(project);
break;
- case TestFunctionOrSet: {
+ case TestFunction: {
TestTreeItem *parent = parentItem();
config = new QtTestConfiguration();
config->setTestCases(QStringList(name()));
@@ -234,7 +234,7 @@ QList<TestConfiguration *> QtTestTreeItem::getSelectedTestConfigurations() const
return result;
}
-QList<TestConfiguration *> QtTestTreeItem::getTestConfigurationsForFile(const Utils::FileName &fileName) const
+QList<TestConfiguration *> QtTestTreeItem::getTestConfigurationsForFile(const Utils::FilePath &fileName) const
{
QList<TestConfiguration *> result;
@@ -245,7 +245,7 @@ QList<TestConfiguration *> QtTestTreeItem::getTestConfigurationsForFile(const Ut
QHash<TestTreeItem *, QStringList> testFunctions;
const QString &file = fileName.toString();
forAllChildren([&testFunctions, &file](TestTreeItem *node) {
- if (node->type() == Type::TestFunctionOrSet && node->filePath() == file) {
+ if (node->type() == Type::TestFunction && node->filePath() == file) {
QTC_ASSERT(node->parentItem(), return);
TestTreeItem *testCase = node->parentItem();
QTC_ASSERT(testCase->type() == Type::TestCase, return);
@@ -287,7 +287,7 @@ TestTreeItem *QtTestTreeItem::find(const TestParseResult *result)
const QtTestParseResult *qtResult = static_cast<const QtTestParseResult *>(result);
return findChildByNameAndInheritance(qtResult->displayName, qtResult->inherited());
}
- case TestFunctionOrSet:
+ case TestFunction:
case TestDataFunction:
case TestSpecialFunction:
return findChildByName(result->name);
@@ -306,12 +306,12 @@ TestTreeItem *QtTestTreeItem::findChild(const TestTreeItem *other)
case GroupNode:
return otherType == TestCase ? findChildByFile(other->filePath()) : nullptr;
case TestCase: {
- if (otherType != TestFunctionOrSet && otherType != TestDataFunction && otherType != TestSpecialFunction)
+ if (otherType != TestFunction && otherType != TestDataFunction && otherType != TestSpecialFunction)
return nullptr;
auto qtOther = static_cast<const QtTestTreeItem *>(other);
return findChildByNameAndInheritance(other->filePath(), qtOther->inherited());
}
- case TestFunctionOrSet:
+ case TestFunction:
case TestDataFunction:
case TestSpecialFunction:
return otherType == TestDataTag ? findChildByName(other->name()) : nullptr;
@@ -326,8 +326,8 @@ bool QtTestTreeItem::modify(const TestParseResult *result)
switch (type()) {
case TestCase:
- return modifyTestCaseContent(result);
- case TestFunctionOrSet:
+ return modifyTestCaseOrSuiteContent(result);
+ case TestFunction:
case TestDataFunction:
case TestSpecialFunction:
return modifyTestFunctionContent(result);
diff --git a/src/plugins/autotest/qtest/qttesttreeitem.h b/src/plugins/autotest/qtest/qttesttreeitem.h
index 3c7f9c4bd7..97ad853580 100644
--- a/src/plugins/autotest/qtest/qttesttreeitem.h
+++ b/src/plugins/autotest/qtest/qttesttreeitem.h
@@ -45,7 +45,7 @@ public:
TestConfiguration *debugConfiguration() const override;
QList<TestConfiguration *> getAllTestConfigurations() const override;
QList<TestConfiguration *> getSelectedTestConfigurations() const override;
- QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FileName &fileName) const override;
+ QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FilePath &fileName) const override;
TestTreeItem *find(const TestParseResult *result) override;
TestTreeItem *findChild(const TestTreeItem *other) override;
bool modify(const TestParseResult *result) override;
diff --git a/src/plugins/autotest/qtest/qttestvisitors.cpp b/src/plugins/autotest/qtest/qttestvisitors.cpp
index b6d6992e2d..58a69f2dbf 100644
--- a/src/plugins/autotest/qtest/qttestvisitors.cpp
+++ b/src/plugins/autotest/qtest/qttestvisitors.cpp
@@ -82,7 +82,7 @@ bool TestVisitor::visit(CPlusPlus::Class *symbol)
else if (name.endsWith("_data"))
locationAndType.m_type = TestTreeItem::TestDataFunction;
else
- locationAndType.m_type = TestTreeItem::TestFunctionOrSet;
+ locationAndType.m_type = TestTreeItem::TestFunction;
locationAndType.m_inherited = m_inherited;
m_privSlots.insert(className + "::" + name, locationAndType);
}
diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp
index c4f7e7963a..2542325510 100644
--- a/src/plugins/autotest/quick/quicktestparser.cpp
+++ b/src/plugins/autotest/quick/quicktestparser.cpp
@@ -144,7 +144,7 @@ QList<QmlJS::Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(c
// make sure even files not listed in pro file are available inside the snapshot
QFutureInterface<void> future;
QmlJS::PathsAndLanguages paths;
- paths.maybeInsert(Utils::FileName::fromString(srcDir), QmlJS::Dialect::Qml);
+ paths.maybeInsert(Utils::FilePath::fromString(srcDir), QmlJS::Dialect::Qml);
QmlJS::ModelManagerInterface::importScan(future, qmlJsMM->workingCopy(), paths, qmlJsMM,
false /*emitDocumentChanges*/, false /*onlyTheLib*/, true /*forceRescan*/ );
@@ -276,7 +276,7 @@ void QuickTestParser::handleDirectoryChanged(const QString &directory)
});
if (timestampChanged) {
QmlJS::PathsAndLanguages paths;
- paths.maybeInsert(Utils::FileName::fromString(directory), QmlJS::Dialect::Qml);
+ paths.maybeInsert(Utils::FilePath::fromString(directory), QmlJS::Dialect::Qml);
QFutureInterface<void> future;
QmlJS::ModelManagerInterface *qmlJsMM = QmlJS::ModelManagerInterface::instance();
QmlJS::ModelManagerInterface::importScan(future, qmlJsMM->workingCopy(), paths, qmlJsMM,
diff --git a/src/plugins/autotest/quick/quicktesttreeitem.cpp b/src/plugins/autotest/quick/quicktesttreeitem.cpp
index 6bc57a0e38..52d3796463 100644
--- a/src/plugins/autotest/quick/quicktesttreeitem.cpp
+++ b/src/plugins/autotest/quick/quicktesttreeitem.cpp
@@ -65,7 +65,7 @@ QVariant QuickTestTreeItem::data(int column, int role) const
return QVariant();
case TestCase:
return name().isEmpty() ? QVariant() : checked();
- case TestFunctionOrSet:
+ case TestFunction:
return (parentItem() && !parentItem()->name().isEmpty()) ? checked() : QVariant();
default:
return checked();
@@ -78,7 +78,7 @@ QVariant QuickTestTreeItem::data(int column, int role) const
return true;
case TestCase:
return name().isEmpty();
- case TestFunctionOrSet:
+ case TestFunction:
return parentItem() ? parentItem()->name().isEmpty() : false;
default:
return false;
@@ -97,7 +97,7 @@ Qt::ItemFlags QuickTestTreeItem::flags(int column) const
if (name().isEmpty())
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
break;
- case TestFunctionOrSet:
+ case TestFunction:
if (parentItem()->name().isEmpty())
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
break;
@@ -111,7 +111,7 @@ bool QuickTestTreeItem::canProvideTestConfiguration() const
switch (type()) {
case TestCase:
return !name().isEmpty();
- case TestFunctionOrSet:
+ case TestFunction:
return !parentItem()->name().isEmpty();
default:
return false;
@@ -134,7 +134,7 @@ TestConfiguration *QuickTestTreeItem::testConfiguration() const
const QString testName = name();
QStringList testFunctions;
forFirstLevelChildren([&testFunctions, &testName](TestTreeItem *child) {
- if (child->type() == TestTreeItem::TestFunctionOrSet)
+ if (child->type() == TestTreeItem::TestFunction)
testFunctions << testName + "::" + child->name();
});
config = new QuickTestConfiguration;
@@ -143,7 +143,7 @@ TestConfiguration *QuickTestTreeItem::testConfiguration() const
config->setProject(project);
break;
}
- case TestFunctionOrSet: {
+ case TestFunction: {
TestTreeItem *parent = parentItem();
QStringList testFunction(parent->name() + "::" + name());
config = new QuickTestConfiguration;
@@ -177,7 +177,7 @@ static void testConfigurationFromCheckState(const TestTreeItem *item,
const QString testName = item->name();
QStringList testFunctions;
item->forFirstLevelChildren([&testFunctions, &testName](TestTreeItem *child) {
- if (child->checked() == Qt::Checked && child->type() == TestTreeItem::TestFunctionOrSet)
+ if (child->checked() == Qt::Checked && child->type() == TestTreeItem::TestFunction)
testFunctions << testName + "::" + child->name();
});
if (foundProFiles.contains(item->proFile())) {
@@ -280,7 +280,7 @@ QList<TestConfiguration *> QuickTestTreeItem::getSelectedTestConfigurations() co
return result;
}
-QList<TestConfiguration *> QuickTestTreeItem::getTestConfigurationsForFile(const Utils::FileName &fileName) const
+QList<TestConfiguration *> QuickTestTreeItem::getTestConfigurationsForFile(const Utils::FilePath &fileName) const
{
QList<TestConfiguration *> result;
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
@@ -290,7 +290,7 @@ QList<TestConfiguration *> QuickTestTreeItem::getTestConfigurationsForFile(const
QHash<TestTreeItem *, QStringList> testFunctions;
const QString &file = fileName.toString();
forAllChildren([&testFunctions, &file](TestTreeItem *node) {
- if (node->type() == Type::TestFunctionOrSet && node->filePath() == file) {
+ if (node->type() == Type::TestFunction && node->filePath() == file) {
QTC_ASSERT(node->parentItem(), return);
TestTreeItem *testCase = node->parentItem();
QTC_ASSERT(testCase->type() == Type::TestCase, return);
@@ -349,7 +349,7 @@ TestTreeItem *QuickTestTreeItem::findChild(const TestTreeItem *other)
case GroupNode:
return findChildByFileAndType(other->filePath(), otherType);
case TestCase:
- if (otherType != TestFunctionOrSet && otherType != TestDataFunction && otherType != TestSpecialFunction)
+ if (otherType != TestFunction && otherType != TestDataFunction && otherType != TestSpecialFunction)
return nullptr;
return name().isEmpty() ? findChildByNameAndFile(other->name(), other->filePath())
: findChildByName(other->name());
@@ -364,8 +364,8 @@ bool QuickTestTreeItem::modify(const TestParseResult *result)
switch (type()) {
case TestCase:
- return result->name.isEmpty() ? false : modifyTestCaseContent(result);
- case TestFunctionOrSet:
+ return result->name.isEmpty() ? false : modifyTestCaseOrSuiteContent(result);
+ case TestFunction:
case TestDataFunction:
case TestSpecialFunction:
return name().isEmpty() ? modifyLineAndColumn(result)
diff --git a/src/plugins/autotest/quick/quicktesttreeitem.h b/src/plugins/autotest/quick/quicktesttreeitem.h
index b1d49065f3..b9f06d6a07 100644
--- a/src/plugins/autotest/quick/quicktesttreeitem.h
+++ b/src/plugins/autotest/quick/quicktesttreeitem.h
@@ -45,7 +45,7 @@ public:
TestConfiguration *debugConfiguration() const override;
QList<TestConfiguration *> getAllTestConfigurations() const override;
QList<TestConfiguration *> getSelectedTestConfigurations() const override;
- QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FileName &fileName) const override;
+ QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FilePath &fileName) const override;
TestTreeItem *find(const TestParseResult *result) override;
TestTreeItem *findChild(const TestTreeItem *other) override;
bool modify(const TestParseResult *result) override;
diff --git a/src/plugins/autotest/quick/quicktestvisitors.cpp b/src/plugins/autotest/quick/quicktestvisitors.cpp
index cbc5f9b2a2..f9934e735d 100644
--- a/src/plugins/autotest/quick/quicktestvisitors.cpp
+++ b/src/plugins/autotest/quick/quicktestvisitors.cpp
@@ -146,7 +146,7 @@ bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast)
else if (name.endsWith("_data"))
locationAndType.m_type = TestTreeItem::TestDataFunction;
else
- locationAndType.m_type = TestTreeItem::TestFunctionOrSet;
+ locationAndType.m_type = TestTreeItem::TestFunction;
m_testFunctions.insert(name.toString(), locationAndType);
}
diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp
index 1449816fc0..c944073dc7 100644
--- a/src/plugins/autotest/testcodeparser.cpp
+++ b/src/plugins/autotest/testcodeparser.cpp
@@ -171,28 +171,6 @@ void TestCodeParser::updateTestTree(ITestParser *parser)
scanForTests(QStringList(), parser);
}
-static QStringList filterFiles(const QString &projectDir, const QStringList &files)
-{
- const QSharedPointer<TestSettings> &settings = AutotestPlugin::settings();
- const QSet<QString> &filters = settings->whiteListFilters.toSet(); // avoid duplicates
- if (!settings->filterScan || filters.isEmpty())
- return files;
- QStringList finalResult;
- for (const QString &file : files) {
- // apply filter only below project directory if file is part of a project
- const QString &fileToProcess = file.startsWith(projectDir)
- ? file.mid(projectDir.size())
- : file;
- for (const QString &filter : filters) {
- if (fileToProcess.contains(filter)) {
- finalResult.push_back(file);
- break;
- }
- }
- }
- return finalResult;
-}
-
// used internally to indicate a parse that failed due to having triggered a parse for a file that
// is not (yet) part of the CppModelManager's snapshot
static bool parsingHasFailed;
@@ -208,7 +186,7 @@ void TestCodeParser::onDocumentUpdated(const QString &fileName, bool isQmlFile)
if (!project)
return;
// Quick tests: qml files aren't necessarily listed inside project files
- if (!isQmlFile && !project->isKnownFile(Utils::FileName::fromString(fileName)))
+ if (!isQmlFile && !project->isKnownFile(Utils::FilePath::fromString(fileName)))
return;
scanForTests(QStringList(fileName));
@@ -343,7 +321,7 @@ void TestCodeParser::scanForTests(const QStringList &fileList, ITestParser *pars
return;
QStringList list;
if (isFullParse) {
- list = Utils::transform(project->files(Project::SourceFiles), &Utils::FileName::toString);
+ list = Utils::transform(project->files(Project::SourceFiles), &Utils::FilePath::toString);
if (list.isEmpty()) {
// at least project file should be there, but might happen if parsing current project
// takes too long, especially when opening sessions holding multiple projects
@@ -379,7 +357,6 @@ void TestCodeParser::scanForTests(const QStringList &fileList, ITestParser *pars
m_model->markForRemoval(filePath);
}
- list = filterFiles(project->projectDirectory().toString(), list);
if (list.isEmpty()) {
if (isFullParse) {
Core::MessageManager::instance()->write(
diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp
index 1f9b73e77c..6f7078eefb 100644
--- a/src/plugins/autotest/testconfiguration.cpp
+++ b/src/plugins/autotest/testconfiguration.cpp
@@ -53,11 +53,10 @@ TestConfiguration::~TestConfiguration()
m_testCases.clear();
}
-static bool isLocal(RunConfiguration *runConfiguration)
+static bool isLocal(Target *target)
{
- Target *target = runConfiguration ? runConfiguration->target() : nullptr;
Kit *kit = target ? target->kit() : nullptr;
- return DeviceTypeKitInformation::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
+ return DeviceTypeKitAspect::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
}
static QString ensureExeEnding(const QString& file)
@@ -93,8 +92,7 @@ void TestConfiguration::completeTestInformation(ProjectExplorer::RunConfiguratio
m_runnable = rc->runnable();
m_displayName = rc->displayName();
- const QString buildKey = rc->buildKey();
- BuildTargetInfo targetInfo = target->applicationTargets().buildTargetInfo(buildKey);
+ BuildTargetInfo targetInfo = rc->buildTargetInfo();
if (!targetInfo.targetFilePath.isEmpty())
m_runnable.executable = ensureExeEnding(targetInfo.targetFilePath.toString());
@@ -142,7 +140,7 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
const QSet<QString> buildSystemTargets = m_buildTargets;
qCDebug(LOG) << "BuildSystemTargets\n " << buildSystemTargets;
BuildTargetInfo targetInfo
- = Utils::findOrDefault(target->applicationTargets().list,
+ = Utils::findOrDefault(target->applicationTargets(),
[&buildSystemTargets] (const BuildTargetInfo &bti) {
return buildSystemTargets.contains(bti.buildKey);
});
@@ -150,7 +148,7 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
// there would be no BuildTargetInfo that could match
if (targetInfo.targetFilePath.isEmpty()) {
qCDebug(LOG) << "BuildTargetInfos";
- const QList<BuildTargetInfo> buildTargets = target->applicationTargets().list;
+ const QList<BuildTargetInfo> buildTargets = target->applicationTargets();
// if there is only one build target just use it (but be honest that we're deducing)
if (buildTargets.size() == 1) {
targetInfo = buildTargets.first();
@@ -184,7 +182,7 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
qCDebug(LOG) << "Iterating run configurations";
for (RunConfiguration *runConfig : target->runConfigurations()) {
qCDebug(LOG) << "RunConfiguration" << runConfig->id();
- if (!isLocal(runConfig)) { // TODO add device support
+ if (!isLocal(target)) { // TODO add device support
qCDebug(LOG) << " Skipped as not being local";
continue;
}
@@ -205,7 +203,7 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
m_runnable.executable = currentExecutable;
m_displayName = runConfig->displayName();
if (runMode == TestRunMode::Debug || runMode == TestRunMode::DebugWithoutDeploy)
- m_runConfig = new TestRunConfiguration(runConfig->target(), this);
+ m_runConfig = new TestRunConfiguration(target, this);
break;
}
}
@@ -220,7 +218,7 @@ void TestConfiguration::completeTestInformation(TestRunMode runMode)
qCDebug(LOG) << " Fallback";
// we failed to find a valid runconfiguration - but we've got the executable already
if (auto rc = target->activeRunConfiguration()) {
- if (isLocal(rc)) { // FIXME for now only Desktop support
+ if (isLocal(target)) { // FIXME for now only Desktop support
const Runnable runnable = rc->runnable();
m_runnable.environment = runnable.environment;
m_deducedConfiguration = true;
diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h
index 929731bce3..fcd778c8ec 100644
--- a/src/plugins/autotest/testconfiguration.h
+++ b/src/plugins/autotest/testconfiguration.h
@@ -28,7 +28,7 @@
#include "autotestconstants.h"
#include <projectexplorer/project.h>
-#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/runcontrol.h>
#include <utils/environment.h>
#include <QFutureInterface>
diff --git a/src/plugins/autotest/testeditormark.cpp b/src/plugins/autotest/testeditormark.cpp
index 61e53ef4bd..29ca484c9c 100644
--- a/src/plugins/autotest/testeditormark.cpp
+++ b/src/plugins/autotest/testeditormark.cpp
@@ -29,7 +29,7 @@
namespace Autotest {
namespace Internal {
-TestEditorMark::TestEditorMark(QPersistentModelIndex item, const Utils::FileName &file, int line)
+TestEditorMark::TestEditorMark(QPersistentModelIndex item, const Utils::FilePath &file, int line)
: TextEditor::TextMark(file, line, Core::Id(Constants::TASK_MARK_ID)),
m_item(item)
{
diff --git a/src/plugins/autotest/testeditormark.h b/src/plugins/autotest/testeditormark.h
index c84e8efb73..458bb4f0c0 100644
--- a/src/plugins/autotest/testeditormark.h
+++ b/src/plugins/autotest/testeditormark.h
@@ -35,7 +35,7 @@ namespace Internal {
class TestEditorMark : public TextEditor::TextMark
{
public:
- TestEditorMark(QPersistentModelIndex item, const Utils::FileName &file, int line);
+ TestEditorMark(QPersistentModelIndex item, const Utils::FilePath &file, int line);
bool isClickable() const override { return true; }
void clicked() override;
diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp
index 363fd1a3b4..9899fcc32a 100644
--- a/src/plugins/autotest/testnavigationwidget.cpp
+++ b/src/plugins/autotest/testnavigationwidget.cpp
@@ -197,7 +197,6 @@ QList<QToolButton *> TestNavigationWidget::createToolButtons()
m_filterButton->setIcon(Utils::Icons::FILTER.icon());
m_filterButton->setToolTip(tr("Filter Test Tree"));
m_filterButton->setProperty("noArrow", true);
- m_filterButton->setAutoRaise(true);
m_filterButton->setPopupMode(QToolButton::InstantPopup);
m_filterMenu = new QMenu(m_filterButton);
initializeFilterMenu();
@@ -237,7 +236,7 @@ void TestNavigationWidget::onItemActivated(const QModelIndex &index)
void TestNavigationWidget::onSortClicked()
{
if (m_sortAlphabetically) {
- m_sort->setIcon(Icons::SORT_ALPHABETICALLY.icon());
+ m_sort->setIcon(Utils::Icons::SORT_ALPHABETICALLY_TOOLBAR.icon());
m_sort->setToolTip(tr("Sort Alphabetically"));
m_sortFilterModel->setSortMode(TestTreeItem::Naturally);
} else {
diff --git a/src/plugins/autotest/testoutputreader.cpp b/src/plugins/autotest/testoutputreader.cpp
index ff96d10e79..36da35543b 100644
--- a/src/plugins/autotest/testoutputreader.cpp
+++ b/src/plugins/autotest/testoutputreader.cpp
@@ -74,11 +74,11 @@ void TestOutputReader::reportCrash()
{
TestResultPtr result = createDefaultResult();
result->setDescription(tr("Test executable crashed."));
- result->setResult(Result::MessageFatal);
+ result->setResult(ResultType::MessageFatal);
m_futureInterface.reportResult(result);
}
-void TestOutputReader::createAndReportResult(const QString &message, Result::Type type)
+void TestOutputReader::createAndReportResult(const QString &message, ResultType type)
{
TestResultPtr result = createDefaultResult();
result->setDescription(message);
diff --git a/src/plugins/autotest/testoutputreader.h b/src/plugins/autotest/testoutputreader.h
index 7c1f7d0f13..87216a2570 100644
--- a/src/plugins/autotest/testoutputreader.h
+++ b/src/plugins/autotest/testoutputreader.h
@@ -45,8 +45,11 @@ public:
void processOutput(const QByteArray &output);
virtual void processStdError(const QByteArray &outputLineWithNewLine);
void reportCrash();
- void createAndReportResult(const QString &message, Result::Type type);
+ void createAndReportResult(const QString &message, ResultType type);
bool hadValidOutput() const { return m_hadValidOutput; }
+ int disabledTests() const { return m_disabled; }
+ bool hasSummary() const { return !m_summary.isEmpty(); }
+ QHash<ResultType, int> summary() const { return m_summary; }
void setId(const QString &id) { m_id = id; }
QString id() const { return m_id; }
@@ -63,6 +66,8 @@ protected:
QProcess *m_testApplication; // not owned
QString m_buildDir;
QString m_id;
+ QHash<ResultType, int> m_summary;
+ int m_disabled = -1;
private:
bool m_hadValidOutput = false;
};
diff --git a/src/plugins/autotest/testresult.cpp b/src/plugins/autotest/testresult.cpp
index ea4261a453..e9ff367ef9 100644
--- a/src/plugins/autotest/testresult.cpp
+++ b/src/plugins/autotest/testresult.cpp
@@ -31,22 +31,6 @@
namespace Autotest {
namespace Internal {
-FaultyTestResult::FaultyTestResult(Result::Type result, const QString &description)
-{
- setResult(result);
- setDescription(description);
-}
-
-TestResult::TestResult()
- : TestResult(QString())
-{
-}
-
-TestResult::TestResult(const QString &name)
- : m_name(name)
-{
-}
-
TestResult::TestResult(const QString &id, const QString &name)
: m_id(id)
, m_name(name)
@@ -55,7 +39,7 @@ TestResult::TestResult(const QString &id, const QString &name)
const QString TestResult::outputString(bool selected) const
{
- if (m_result == Result::Application)
+ if (m_result == ResultType::Application)
return m_id;
return selected ? m_description : m_description.split('\n').first();
}
@@ -65,138 +49,127 @@ const TestTreeItem *TestResult::findTestTreeItem() const
return nullptr;
}
-Result::Type TestResult::resultFromString(const QString &resultString)
+ResultType TestResult::resultFromString(const QString &resultString)
{
if (resultString == "pass")
- return Result::Pass;
+ return ResultType::Pass;
if (resultString == "fail" || resultString == "fail!")
- return Result::Fail;
+ return ResultType::Fail;
if (resultString == "xfail")
- return Result::ExpectedFail;
+ return ResultType::ExpectedFail;
if (resultString == "xpass")
- return Result::UnexpectedPass;
+ return ResultType::UnexpectedPass;
if (resultString == "skip")
- return Result::Skip;
+ return ResultType::Skip;
if (resultString == "result")
- return Result::Benchmark;
+ return ResultType::Benchmark;
if (resultString == "qdebug")
- return Result::MessageDebug;
+ return ResultType::MessageDebug;
if (resultString == "qinfo" || resultString == "info")
- return Result::MessageInfo;
+ return ResultType::MessageInfo;
if (resultString == "warn" || resultString == "qwarn" || resultString == "warning")
- return Result::MessageWarn;
+ return ResultType::MessageWarn;
if (resultString == "qfatal")
- return Result::MessageFatal;
+ return ResultType::MessageFatal;
if ((resultString == "system") || (resultString == "qsystem"))
- return Result::MessageSystem;
+ return ResultType::MessageSystem;
if (resultString == "bpass")
- return Result::BlacklistedPass;
+ return ResultType::BlacklistedPass;
if (resultString == "bfail")
- return Result::BlacklistedFail;
+ return ResultType::BlacklistedFail;
if (resultString == "bxpass")
- return Result::BlacklistedXPass;
+ return ResultType::BlacklistedXPass;
if (resultString == "bxfail")
- return Result::BlacklistedXFail;
+ return ResultType::BlacklistedXFail;
qDebug("Unexpected test result: %s", qPrintable(resultString));
- return Result::Invalid;
+ return ResultType::Invalid;
}
-Result::Type TestResult::toResultType(int rt)
+ResultType TestResult::toResultType(int rt)
{
- if (rt < Result::FIRST_TYPE || rt > Result::LAST_TYPE)
- return Result::Invalid;
+ if (rt < int(ResultType::FIRST_TYPE) || rt > int(ResultType::LAST_TYPE))
+ return ResultType::Invalid;
- return Result::Type(rt);
+ return ResultType(rt);
}
-QString TestResult::resultToString(const Result::Type type)
+QString TestResult::resultToString(const ResultType type)
{
switch (type) {
- case Result::Pass:
- case Result::MessageTestCaseSuccess:
- case Result::MessageTestCaseSuccessWarn:
+ case ResultType::Pass:
return QString("PASS");
- case Result::Fail:
- case Result::MessageTestCaseFail:
- case Result::MessageTestCaseFailWarn:
+ case ResultType::Fail:
return QString("FAIL");
- case Result::ExpectedFail:
+ case ResultType::ExpectedFail:
return QString("XFAIL");
- case Result::UnexpectedPass:
+ case ResultType::UnexpectedPass:
return QString("XPASS");
- case Result::Skip:
+ case ResultType::Skip:
return QString("SKIP");
- case Result::Benchmark:
+ case ResultType::Benchmark:
return QString("BENCH");
- case Result::MessageDebug:
+ case ResultType::MessageDebug:
return QString("DEBUG");
- case Result::MessageInfo:
+ case ResultType::MessageInfo:
return QString("INFO");
- case Result::MessageWarn:
+ case ResultType::MessageWarn:
return QString("WARN");
- case Result::MessageFatal:
+ case ResultType::MessageFatal:
return QString("FATAL");
- case Result::MessageSystem:
+ case ResultType::MessageSystem:
return QString("SYSTEM");
- case Result::BlacklistedPass:
+ case ResultType::BlacklistedPass:
return QString("BPASS");
- case Result::BlacklistedFail:
+ case ResultType::BlacklistedFail:
return QString("BFAIL");
- case Result::BlacklistedXPass:
+ case ResultType::BlacklistedXPass:
return QString("BXPASS");
- case Result::BlacklistedXFail:
+ case ResultType::BlacklistedXFail:
return QString("BXFAIL");
- case Result::MessageLocation:
- case Result::Application:
+ case ResultType::MessageLocation:
+ case ResultType::Application:
return QString();
default:
- if (type >= Result::INTERNAL_MESSAGES_BEGIN && type <= Result::INTERNAL_MESSAGES_END)
+ if (type >= ResultType::INTERNAL_MESSAGES_BEGIN && type <= ResultType::INTERNAL_MESSAGES_END)
return QString();
return QString("UNKNOWN");
}
}
-QColor TestResult::colorForType(const Result::Type type)
+QColor TestResult::colorForType(const ResultType type)
{
- if (type >= Result::INTERNAL_MESSAGES_BEGIN && type <= Result::INTERNAL_MESSAGES_END)
+ if (type >= ResultType::INTERNAL_MESSAGES_BEGIN && type <= ResultType::INTERNAL_MESSAGES_END)
return QColor("transparent");
Utils::Theme *creatorTheme = Utils::creatorTheme();
switch (type) {
- case Result::Pass:
+ case ResultType::Pass:
return creatorTheme->color(Utils::Theme::OutputPanes_TestPassTextColor);
- case Result::Fail:
+ case ResultType::Fail:
return creatorTheme->color(Utils::Theme::OutputPanes_TestFailTextColor);
- case Result::ExpectedFail:
+ case ResultType::ExpectedFail:
return creatorTheme->color(Utils::Theme::OutputPanes_TestXFailTextColor);
- case Result::UnexpectedPass:
+ case ResultType::UnexpectedPass:
return creatorTheme->color(Utils::Theme::OutputPanes_TestXPassTextColor);
- case Result::Skip:
+ case ResultType::Skip:
return creatorTheme->color(Utils::Theme::OutputPanes_TestSkipTextColor);
- case Result::MessageDebug:
- case Result::MessageInfo:
+ case ResultType::MessageDebug:
+ case ResultType::MessageInfo:
return creatorTheme->color(Utils::Theme::OutputPanes_TestDebugTextColor);
- case Result::MessageWarn:
+ case ResultType::MessageWarn:
return creatorTheme->color(Utils::Theme::OutputPanes_TestWarnTextColor);
- case Result::MessageFatal:
- case Result::MessageSystem:
+ case ResultType::MessageFatal:
+ case ResultType::MessageSystem:
return creatorTheme->color(Utils::Theme::OutputPanes_TestFatalTextColor);
- case Result::BlacklistedPass:
- case Result::BlacklistedFail:
- case Result::BlacklistedXPass:
- case Result::BlacklistedXFail:
+ case ResultType::BlacklistedPass:
+ case ResultType::BlacklistedFail:
+ case ResultType::BlacklistedXPass:
+ case ResultType::BlacklistedXFail:
default:
return creatorTheme->color(Utils::Theme::OutputPanes_StdOutTextColor);
}
}
-bool TestResult::isMessageCaseStart(const Result::Type type)
-{
- return type == Result::MessageTestCaseStart || type == Result::MessageTestCaseSuccess
- || type == Result::MessageTestCaseFail || type == Result::MessageTestCaseSuccessWarn
- || type == Result::MessageTestCaseFailWarn || type == Result::MessageIntermediate;
-}
-
bool TestResult::isDirectParentOf(const TestResult *other, bool * /*needsIntermediate*/) const
{
QTC_ASSERT(other, return false);
diff --git a/src/plugins/autotest/testresult.h b/src/plugins/autotest/testresult.h
index a1e1d2e7bf..84fc2c144a 100644
--- a/src/plugins/autotest/testresult.h
+++ b/src/plugins/autotest/testresult.h
@@ -37,8 +37,8 @@ namespace Internal {
class TestTreeItem;
-namespace Result{
-enum Type {
+enum class ResultType {
+ // result types (have icon, color, short text)
Pass, FIRST_TYPE = Pass,
Fail,
ExpectedFail,
@@ -48,37 +48,40 @@ enum Type {
BlacklistedFail,
BlacklistedXPass,
BlacklistedXFail,
+
+ // special (message) types (have icon, color, short text)
Benchmark,
MessageDebug,
MessageInfo,
MessageWarn,
MessageFatal,
MessageSystem,
- MessageLocation,
+ // special message - get's icon (but no color/short text) from parent
+ MessageLocation,
+ // anything below is an internal message (or a pure message without icon)
MessageInternal, INTERNAL_MESSAGES_BEGIN = MessageInternal,
- MessageDisabledTests,
- MessageTestCaseStart,
- MessageTestCaseSuccess,
- MessageTestCaseSuccessWarn,
- MessageTestCaseFail,
- MessageTestCaseFailWarn,
- MessageTestCaseEnd,
- MessageIntermediate,
+ // start item (get icon/short text depending on children)
+ TestStart,
+ // usually no icon/short text - more or less an indicator (and can contain test duration)
+ TestEnd,
+ // special global (temporary) message
MessageCurrentTest, INTERNAL_MESSAGES_END = MessageCurrentTest,
- Application,
-
- Invalid,
+ Application, // special.. not to be used outside of testresultmodel
+ Invalid, // indicator for unknown result items
LAST_TYPE = Invalid
};
+
+inline uint qHash(const ResultType &result)
+{
+ return QT_PREPEND_NAMESPACE(qHash(int(result)));
}
class TestResult
{
public:
- TestResult();
- explicit TestResult(const QString &name);
+ TestResult() = default;
TestResult(const QString &id, const QString &name);
virtual ~TestResult() {}
@@ -87,7 +90,7 @@ public:
QString id() const { return m_id; }
QString name() const { return m_name; }
- Result::Type result() const { return m_result; }
+ ResultType result() const { return m_result; }
QString description() const { return m_description; }
QString fileName() const { return m_file; }
int line() const { return m_line; }
@@ -95,22 +98,20 @@ public:
void setDescription(const QString &description) { m_description = description; }
void setFileName(const QString &fileName) { m_file = fileName; }
void setLine(int line) { m_line = line; }
- void setResult(Result::Type type) { m_result = type; }
+ void setResult(ResultType type) { m_result = type; }
- static Result::Type resultFromString(const QString &resultString);
- static Result::Type toResultType(int rt);
- static QString resultToString(const Result::Type type);
- static QColor colorForType(const Result::Type type);
- static bool isMessageCaseStart(const Result::Type type);
+ static ResultType resultFromString(const QString &resultString);
+ static ResultType toResultType(int rt);
+ static QString resultToString(const ResultType type);
+ static QColor colorForType(const ResultType type);
virtual bool isDirectParentOf(const TestResult *other, bool *needsIntermediate) const;
virtual bool isIntermediateFor(const TestResult *other) const;
virtual TestResult *createIntermediateResultFor(const TestResult *other);
-
private:
QString m_id;
QString m_name;
- Result::Type m_result = Result::Invalid;
+ ResultType m_result = ResultType::Invalid; // the real result..
QString m_description;
QString m_file;
int m_line = 0;
@@ -118,14 +119,8 @@ private:
using TestResultPtr = QSharedPointer<TestResult>;
-class FaultyTestResult : public TestResult
-{
-public:
- FaultyTestResult(Result::Type result, const QString &description);
-};
-
} // namespace Internal
} // namespace Autotest
Q_DECLARE_METATYPE(Autotest::Internal::TestResult)
-Q_DECLARE_METATYPE(Autotest::Internal::Result::Type)
+Q_DECLARE_METATYPE(Autotest::Internal::ResultType)
diff --git a/src/plugins/autotest/testresultdelegate.cpp b/src/plugins/autotest/testresultdelegate.cpp
index d70b6fa39e..f5486149af 100644
--- a/src/plugins/autotest/testresultdelegate.cpp
+++ b/src/plugins/autotest/testresultdelegate.cpp
@@ -40,12 +40,6 @@ namespace Internal {
constexpr int outputLimit = 100000;
-static bool isSummaryItem(Result::Type type)
-{
- return type == Result::MessageTestCaseSuccess || type == Result::MessageTestCaseSuccessWarn
- || type == Result::MessageTestCaseFail || type == Result::MessageTestCaseFailWarn;
-}
-
TestResultDelegate::TestResultDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
@@ -89,12 +83,14 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
painter->drawPixmap(positions.left(), positions.top(),
icon.pixmap(window, QSize(positions.iconSize(), positions.iconSize())));
- QString typeStr = TestResult::resultToString(testResult->result());
+ TestResultItem *item = resultFilterModel->itemForIndex(index);
+ QTC_ASSERT(item, painter->restore(); return);
+ const QString typeStr = item->resultString();
if (selected) {
painter->drawText(positions.typeAreaLeft(), positions.top() + fm.ascent(), typeStr);
} else {
QPen tmp = painter->pen();
- if (isSummaryItem(testResult->result()))
+ if (testResult->result() == ResultType::TestStart)
painter->setPen(opt.palette.mid().color());
else
painter->setPen(TestResult::colorForType(testResult->result()));
diff --git a/src/plugins/autotest/testresultdelegate.h b/src/plugins/autotest/testresultdelegate.h
index 5921ebdc92..a3b2cb7c5f 100644
--- a/src/plugins/autotest/testresultdelegate.h
+++ b/src/plugins/autotest/testresultdelegate.h
@@ -65,7 +65,7 @@ private:
m_maxFileLength = srcModel->maxWidthOfFileName(options.font);
m_maxLineLength = srcModel->maxWidthOfLineNumber(options.font);
m_realFileLength = m_maxFileLength;
- m_typeAreaWidth = QFontMetrics(options.font).width("XXXXXXXX");
+ m_typeAreaWidth = QFontMetrics(options.font).horizontalAdvance("XXXXXXXX");
m_indentation = options.widget ? options.widget->style()->pixelMetric(
QStyle::PM_TreeViewIndentation, &options) : 0;
diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp
index deb6e1dfae..a3c6ec28a8 100644
--- a/src/plugins/autotest/testresultmodel.cpp
+++ b/src/plugins/autotest/testresultmodel.cpp
@@ -23,10 +23,11 @@
**
****************************************************************************/
+#include "testresultmodel.h"
#include "autotesticons.h"
#include "autotestplugin.h"
#include "testresultdelegate.h"
-#include "testresultmodel.h"
+#include "testrunner.h"
#include "testsettings.h"
#include <projectexplorer/projectexplorericons.h>
@@ -45,7 +46,7 @@ TestResultItem::TestResultItem(const TestResultPtr &testResult)
{
}
-static QIcon testResultIcon(Result::Type result) {
+static QIcon testResultIcon(ResultType result) {
const static QIcon icons[] = {
Icons::RESULT_PASS.icon(),
Icons::RESULT_FAIL.icon(),
@@ -62,29 +63,27 @@ static QIcon testResultIcon(Result::Type result) {
Icons::RESULT_MESSAGEWARN.icon(),
Icons::RESULT_MESSAGEFATAL.icon(),
Icons::RESULT_MESSAGEFATAL.icon(), // System gets same handling as Fatal for now
- QIcon(),
- Icons::RESULT_MESSAGEPASSWARN.icon(),
- Icons::RESULT_MESSAGEFAILWARN.icon(),
ProjectExplorer::Icons::DESKTOP_DEVICE.icon(), // for now
}; // provide an icon for unknown??
- if (result < 0 || result >= Result::MessageInternal) {
+ if (result < ResultType::FIRST_TYPE || result >= ResultType::MessageInternal) {
switch (result) {
- case Result::MessageTestCaseSuccess:
- return icons[Result::Pass];
- case Result::MessageTestCaseFail:
- return icons[Result::Fail];
- case Result::MessageTestCaseSuccessWarn:
- return icons[16];
- case Result::MessageTestCaseFailWarn:
- return icons[17];
- case Result::Application:
- return icons[18];
+ case ResultType::Application:
+ return icons[15];
default:
return QIcon();
}
}
- return icons[result];
+ return icons[int(result)];
+}
+
+static QIcon testSummaryIcon(const Utils::optional<TestResultItem::SummaryEvaluation> &summary)
+{
+ if (!summary)
+ return QIcon();
+ if (summary->failed)
+ return summary->warnings ? Icons::RESULT_MESSAGEFAILWARN.icon() : Icons::RESULT_FAIL.icon();
+ return summary->warnings ? Icons::RESULT_MESSAGEPASSWARN.icon() : Icons::RESULT_PASS.icon();
}
QVariant TestResultItem::data(int column, int role) const
@@ -93,9 +92,11 @@ QVariant TestResultItem::data(int column, int role) const
case Qt::DecorationRole: {
if (!m_testResult)
return QVariant();
- const Result::Type result = m_testResult->result();
- if (result == Result::MessageLocation && parent())
+ const ResultType result = m_testResult->result();
+ if (result == ResultType::MessageLocation && parent())
return parent()->data(column, role);
+ if (result == ResultType::TestStart)
+ return testSummaryIcon(m_summaryResult);
return testResultIcon(result);
}
case Qt::DisplayRole:
@@ -112,50 +113,72 @@ void TestResultItem::updateDescription(const QString &description)
m_testResult->setDescription(description);
}
-void TestResultItem::updateResult(bool &changed, Result::Type addedChildType)
+static bool isSignificant(ResultType type)
+{
+ switch (type) {
+ case ResultType::Benchmark:
+ case ResultType::MessageInfo:
+ case ResultType::MessageInternal:
+ case ResultType::TestEnd:
+ return false;
+ case ResultType::MessageLocation:
+ case ResultType::MessageCurrentTest:
+ case ResultType::Application:
+ case ResultType::Invalid:
+ QTC_ASSERT_STRING("Got unexpedted type in isSignificant check");
+ return false;
+ default:
+ return true;
+ }
+}
+
+void TestResultItem::updateResult(bool &changed, ResultType addedChildType,
+ const Utils::optional<SummaryEvaluation> &summary)
{
changed = false;
- const Result::Type old = m_testResult->result();
- if (old == Result::MessageTestCaseFailWarn) // can't become worse
+ if (m_testResult->result() != ResultType::TestStart)
return;
- if (!TestResult::isMessageCaseStart(old))
+
+ if (!isSignificant(addedChildType) || (addedChildType == ResultType::TestStart && !summary))
return;
- Result::Type newResult = old;
+ if (m_summaryResult.has_value() && m_summaryResult->failed && m_summaryResult->warnings)
+ return; // can't become worse
+
+ SummaryEvaluation newResult = m_summaryResult.value_or(SummaryEvaluation());
switch (addedChildType) {
- case Result::Fail:
- case Result::MessageFatal:
- case Result::UnexpectedPass:
- case Result::MessageTestCaseFail:
- newResult = (old == Result::MessageTestCaseSuccessWarn) ? Result::MessageTestCaseFailWarn
- : Result::MessageTestCaseFail;
+ case ResultType::Fail:
+ case ResultType::MessageFatal:
+ case ResultType::UnexpectedPass:
+ if (newResult.failed)
+ return;
+ newResult.failed = true;
break;
- case Result::MessageTestCaseFailWarn:
- newResult = Result::MessageTestCaseFailWarn;
+ case ResultType::ExpectedFail:
+ case ResultType::MessageWarn:
+ case ResultType::MessageSystem:
+ case ResultType::Skip:
+ case ResultType::BlacklistedFail:
+ case ResultType::BlacklistedPass:
+ case ResultType::BlacklistedXFail:
+ case ResultType::BlacklistedXPass:
+ if (newResult.warnings)
+ return;
+ newResult.warnings = true;
break;
- case Result::ExpectedFail:
- case Result::MessageWarn:
- case Result::MessageSystem:
- case Result::Skip:
- case Result::BlacklistedFail:
- case Result::BlacklistedPass:
- case Result::BlacklistedXFail:
- case Result::BlacklistedXPass:
- case Result::MessageTestCaseSuccessWarn:
- newResult = (old == Result::MessageTestCaseFail) ? Result::MessageTestCaseFailWarn
- : Result::MessageTestCaseSuccessWarn;
- break;
- case Result::Pass:
- case Result::MessageTestCaseSuccess:
- newResult = (old == Result::MessageIntermediate || old == Result::MessageTestCaseStart)
- ? Result::MessageTestCaseSuccess : old;
+ case ResultType::TestStart:
+ if (summary) {
+ newResult.failed |= summary->failed;
+ newResult.warnings |= summary->warnings;
+ }
break;
default:
break;
}
- changed = old != newResult;
+ changed = !m_summaryResult.has_value() || m_summaryResult.value() != newResult;
+
if (changed)
- m_testResult->setResult(newResult);
+ m_summaryResult.emplace(newResult);
}
TestResultItem *TestResultItem::intermediateFor(const TestResultItem *item) const
@@ -165,7 +188,7 @@ TestResultItem *TestResultItem::intermediateFor(const TestResultItem *item) cons
for (int row = childCount() - 1; row >= 0; --row) {
TestResultItem *child = childAt(row);
const TestResult *testResult = child->testResult();
- if (testResult->result() != Result::MessageIntermediate)
+ if (testResult->result() != ResultType::TestStart)
continue;
if (testResult->isIntermediateFor(otherResult))
return child;
@@ -177,17 +200,30 @@ TestResultItem *TestResultItem::createAndAddIntermediateFor(const TestResultItem
{
TestResultPtr result(m_testResult->createIntermediateResultFor(child->testResult()));
QTC_ASSERT(!result.isNull(), return nullptr);
- result->setResult(Result::MessageIntermediate);
+ result->setResult(ResultType::TestStart);
TestResultItem *intermediate = new TestResultItem(result);
appendChild(intermediate);
return intermediate;
}
+QString TestResultItem::resultString() const
+{
+ if (testResult()->result() != ResultType::TestStart)
+ return TestResult::resultToString(testResult()->result());
+ if (!m_summaryResult)
+ return QString();
+ return m_summaryResult->failed ? QString("FAIL") : QString("PASS");
+}
+
/********************************* TestResultModel *****************************************/
TestResultModel::TestResultModel(QObject *parent)
: Utils::TreeModel<TestResultItem>(new TestResultItem(TestResultPtr()), parent)
{
+ connect(TestRunner::instance(), &TestRunner::reportSummary,
+ this, [this](const QString &id, const QHash<ResultType, int> &summary){
+ m_reportedSummary.insert(id, summary);
+ });
}
void TestResultModel::updateParent(const TestResultItem *item)
@@ -198,7 +234,7 @@ void TestResultModel::updateParent(const TestResultItem *item)
if (parentItem == rootItem()) // do not update invisible root item
return;
bool changed = false;
- parentItem->updateResult(changed, item->testResult()->result());
+ parentItem->updateResult(changed, item->testResult()->result(), item->summaryResult());
if (!changed)
return;
emit dataChanged(parentItem->index(), parentItem->index());
@@ -208,12 +244,12 @@ void TestResultModel::updateParent(const TestResultItem *item)
void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoExpand)
{
const int lastRow = rootItem()->childCount() - 1;
- if (testResult->result() == Result::MessageCurrentTest) {
+ if (testResult->result() == ResultType::MessageCurrentTest) {
// MessageCurrentTest should always be the last top level item
if (lastRow >= 0) {
TestResultItem *current = rootItem()->childAt(lastRow);
const TestResult *result = current->testResult();
- if (result && result->result() == Result::MessageCurrentTest) {
+ if (result && result->result() == ResultType::MessageCurrentTest) {
current->updateDescription(testResult->description());
emit dataChanged(current->index(), current->index());
return;
@@ -224,12 +260,9 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
return;
}
- if (testResult->result() == Result::MessageDisabledTests)
- m_disabled += testResult->line();
- m_testResultCount[testResult->result()]++;
+ m_testResultCount[testResult->id()][testResult->result()]++;
TestResultItem *newItem = new TestResultItem(testResult);
-
TestResultItem *root = nullptr;
if (AutotestPlugin::settings()->displayApplication) {
const QString application = testResult->id();
@@ -241,7 +274,7 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
if (!root) {
TestResult *tmpAppResult = new TestResult(application, application);
- tmpAppResult->setResult(Result::Application);
+ tmpAppResult->setResult(ResultType::Application);
root = new TestResultItem(TestResultPtr(tmpAppResult));
if (lastRow >= 0)
rootItem()->insertChild(lastRow, root);
@@ -262,7 +295,7 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
if (lastRow >= 0) {
TestResultItem *current = rootItem()->childAt(lastRow);
const TestResult *result = current->testResult();
- if (result && result->result() == Result::MessageCurrentTest) {
+ if (result && result->result() == ResultType::MessageCurrentTest) {
rootItem()->insertChild(current->index().row(), newItem);
return;
}
@@ -275,7 +308,7 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx
void TestResultModel::removeCurrentTestMessage()
{
TestResultItem *currentMessageItem = rootItem()->findFirstLevelChild([](TestResultItem *it) {
- return (it->testResult()->result() == Result::MessageCurrentTest);
+ return (it->testResult()->result() == ResultType::MessageCurrentTest);
});
if (currentMessageItem)
destroyItem(currentMessageItem);
@@ -285,6 +318,7 @@ void TestResultModel::clearTestResults()
{
clear();
m_testResultCount.clear();
+ m_reportedSummary.clear();
m_disabled = 0;
m_fileNames.clear();
m_maxWidthOfFileName = 0;
@@ -305,7 +339,7 @@ void TestResultModel::recalculateMaxWidthOfFileName(const QFont &font)
m_maxWidthOfFileName = 0;
for (const QString &fileName : m_fileNames) {
int pos = fileName.lastIndexOf('/');
- m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.width(fileName.mid(pos + 1)));
+ m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName.mid(pos + 1)));
}
}
@@ -313,7 +347,7 @@ void TestResultModel::addFileName(const QString &fileName)
{
const QFontMetrics fm(m_measurementFont);
int pos = fileName.lastIndexOf('/');
- m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.width(fileName.mid(pos + 1)));
+ m_maxWidthOfFileName = qMax(m_maxWidthOfFileName, fm.horizontalAdvance(fileName.mid(pos + 1)));
m_fileNames.insert(fileName);
}
@@ -329,11 +363,26 @@ int TestResultModel::maxWidthOfLineNumber(const QFont &font)
if (m_widthOfLineNumber == 0 || font != m_measurementFont) {
QFontMetrics fm(font);
m_measurementFont = font;
- m_widthOfLineNumber = fm.width("88888");
+ m_widthOfLineNumber = fm.horizontalAdvance("88888");
}
return m_widthOfLineNumber;
}
+int TestResultModel::resultTypeCount(ResultType type) const
+{
+ int result = 0;
+
+ for (auto resultsForId : m_testResultCount.values())
+ result += resultsForId.value(type, 0);
+
+ for (auto id : m_reportedSummary.keys()) {
+ if (int counted = m_testResultCount.value(id).value(type))
+ result -= counted;
+ result += m_reportedSummary[id].value(type);
+ }
+ return result;
+}
+
TestResultItem *TestResultModel::findParentItemFor(const TestResultItem *item,
const TestResultItem *startItem) const
{
@@ -387,42 +436,39 @@ TestResultFilterModel::TestResultFilterModel(TestResultModel *sourceModel, QObje
void TestResultFilterModel::enableAllResultTypes(bool enabled)
{
if (enabled) {
- m_enabled << Result::Pass << Result::Fail << Result::ExpectedFail
- << Result::UnexpectedPass << Result::Skip << Result::MessageDebug
- << Result::MessageWarn << Result::MessageInternal << Result::MessageLocation
- << Result::MessageFatal << Result::Invalid << Result::BlacklistedPass
- << Result::BlacklistedFail << Result::BlacklistedXFail << Result::BlacklistedXPass
- << Result::Benchmark << Result::MessageIntermediate
- << Result::MessageCurrentTest << Result::MessageTestCaseStart
- << Result::MessageTestCaseSuccess << Result::MessageTestCaseSuccessWarn
- << Result::MessageTestCaseFail << Result::MessageTestCaseFailWarn
- << Result::MessageTestCaseEnd
- << Result::MessageInfo << Result::MessageSystem << Result::Application;
+ m_enabled << ResultType::Pass << ResultType::Fail << ResultType::ExpectedFail
+ << ResultType::UnexpectedPass << ResultType::Skip << ResultType::MessageDebug
+ << ResultType::MessageWarn << ResultType::MessageInternal << ResultType::MessageLocation
+ << ResultType::MessageFatal << ResultType::Invalid << ResultType::BlacklistedPass
+ << ResultType::BlacklistedFail << ResultType::BlacklistedXFail << ResultType::BlacklistedXPass
+ << ResultType::Benchmark
+ << ResultType::MessageCurrentTest << ResultType::TestStart << ResultType::TestEnd
+ << ResultType::MessageInfo << ResultType::MessageSystem << ResultType::Application;
} else {
m_enabled.clear();
- m_enabled << Result::MessageFatal << Result::MessageSystem;
+ m_enabled << ResultType::MessageFatal << ResultType::MessageSystem;
}
invalidateFilter();
}
-void TestResultFilterModel::toggleTestResultType(Result::Type type)
+void TestResultFilterModel::toggleTestResultType(ResultType type)
{
if (m_enabled.contains(type)) {
m_enabled.remove(type);
- if (type == Result::MessageInternal)
- m_enabled.remove(Result::MessageTestCaseEnd);
- if (type == Result::MessageDebug)
- m_enabled.remove(Result::MessageInfo);
- if (type == Result::MessageWarn)
- m_enabled.remove(Result::MessageSystem);
+ if (type == ResultType::MessageInternal)
+ m_enabled.remove(ResultType::TestEnd);
+ if (type == ResultType::MessageDebug)
+ m_enabled.remove(ResultType::MessageInfo);
+ if (type == ResultType::MessageWarn)
+ m_enabled.remove(ResultType::MessageSystem);
} else {
m_enabled.insert(type);
- if (type == Result::MessageInternal)
- m_enabled.insert(Result::MessageTestCaseEnd);
- if (type == Result::MessageDebug)
- m_enabled.insert(Result::MessageInfo);
- if (type == Result::MessageWarn)
- m_enabled.insert(Result::MessageSystem);
+ if (type == ResultType::MessageInternal)
+ m_enabled.insert(ResultType::TestEnd);
+ if (type == ResultType::MessageDebug)
+ m_enabled.insert(ResultType::MessageInfo);
+ if (type == ResultType::MessageWarn)
+ m_enabled.insert(ResultType::MessageSystem);
}
invalidateFilter();
}
@@ -442,38 +488,41 @@ const TestResult *TestResultFilterModel::testResult(const QModelIndex &index) co
return m_sourceModel->testResult(mapToSource(index));
}
+TestResultItem *TestResultFilterModel::itemForIndex(const QModelIndex &index) const
+{
+ return index.isValid() ? m_sourceModel->itemForIndex(mapToSource(index)) : nullptr;
+}
+
bool TestResultFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex index = m_sourceModel->index(sourceRow, 0, sourceParent);
if (!index.isValid())
return false;
- Result::Type resultType = m_sourceModel->testResult(index)->result();
- switch (resultType) {
- case Result::MessageTestCaseSuccess:
- return m_enabled.contains(Result::Pass);
- case Result::MessageTestCaseFail:
- case Result::MessageTestCaseSuccessWarn:
- case Result::MessageTestCaseFailWarn:
+ ResultType resultType = m_sourceModel->testResult(index)->result();
+ if (resultType == ResultType::TestStart) {
+ TestResultItem *item = m_sourceModel->itemForIndex(index);
+ QTC_ASSERT(item, return false);
+ if (!item->summaryResult())
+ return true;
return acceptTestCaseResult(index);
- default:
- return m_enabled.contains(resultType);
}
+ return m_enabled.contains(resultType);
}
bool TestResultFilterModel::acceptTestCaseResult(const QModelIndex &srcIndex) const
{
for (int row = 0, count = m_sourceModel->rowCount(srcIndex); row < count; ++row) {
const QModelIndex &child = m_sourceModel->index(row, 0, srcIndex);
- Result::Type type = m_sourceModel->testResult(child)->result();
- if (type == Result::MessageTestCaseSuccess)
- type = Result::Pass;
- if (type == Result::MessageTestCaseFail || type == Result::MessageTestCaseFailWarn
- || type == Result::MessageTestCaseSuccessWarn) {
+ TestResultItem *item = m_sourceModel->itemForIndex(child);
+ ResultType type = item->testResult()->result();
+
+ if (type == ResultType::TestStart) {
+ if (!item->summaryResult())
+ return true;
if (acceptTestCaseResult(child))
return true;
- } else if (m_enabled.contains(type)) {
+ } else if (m_enabled.contains(type))
return true;
- }
}
return false;
}
diff --git a/src/plugins/autotest/testresultmodel.h b/src/plugins/autotest/testresultmodel.h
index c240b434bb..6370296ac0 100644
--- a/src/plugins/autotest/testresultmodel.h
+++ b/src/plugins/autotest/testresultmodel.h
@@ -32,6 +32,7 @@
#include <QFont>
#include <QSet>
+#include <utils/optional.h>
#include <utils/treemodel.h>
namespace Autotest {
@@ -44,13 +45,29 @@ public:
QVariant data(int column, int role) const override;
const TestResult *testResult() const { return m_testResult.data(); }
void updateDescription(const QString &description);
- void updateResult(bool &changed, Result::Type addedChildType);
+
+ struct SummaryEvaluation
+ {
+ bool failed = false;
+ bool warnings = false;
+
+ bool operator==(const SummaryEvaluation &other) const
+ { return failed == other.failed && warnings == other.warnings; }
+ bool operator!=(const SummaryEvaluation &other) const
+ { return !(*this == other); }
+ };
+
+ void updateResult(bool &changed, ResultType addedChildType,
+ const Utils::optional<SummaryEvaluation> &summary);
TestResultItem *intermediateFor(const TestResultItem *item) const;
TestResultItem *createAndAddIntermediateFor(const TestResultItem *child);
+ QString resultString() const;
+ Utils::optional<SummaryEvaluation> summaryResult() const { return m_summaryResult; }
private:
TestResultPtr m_testResult;
+ Utils::optional<SummaryEvaluation> m_summaryResult;
};
class TestResultModel : public Utils::TreeModel<TestResultItem>
@@ -67,8 +84,9 @@ public:
int maxWidthOfFileName(const QFont &font);
int maxWidthOfLineNumber(const QFont &font);
- int resultTypeCount(Result::Type type) const { return m_testResultCount.value(type, 0); }
+ int resultTypeCount(ResultType type) const;
int disabledTests() const { return m_disabled; }
+ void raiseDisabledTests(int amount) { m_disabled += amount; }
private:
void recalculateMaxWidthOfFileName(const QFont &font);
@@ -76,7 +94,8 @@ private:
TestResultItem *findParentItemFor(const TestResultItem *item,
const TestResultItem *startItem = nullptr) const;
void updateParent(const TestResultItem *item);
- QMap<Result::Type, int> m_testResultCount;
+ QHash<QString, QMap<ResultType, int>> m_testResultCount;
+ QHash<QString, QHash<ResultType, int>> m_reportedSummary;
int m_widthOfLineNumber = 0;
int m_maxWidthOfFileName = 0;
int m_disabled = 0;
@@ -91,10 +110,11 @@ public:
explicit TestResultFilterModel(TestResultModel *sourceModel, QObject *parent = nullptr);
void enableAllResultTypes(bool enabled);
- void toggleTestResultType(Result::Type type);
+ void toggleTestResultType(ResultType type);
void clearTestResults();
bool hasResults();
const TestResult *testResult(const QModelIndex &index) const;
+ TestResultItem *itemForIndex(const QModelIndex &index) const;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
@@ -102,7 +122,7 @@ protected:
private:
bool acceptTestCaseResult(const QModelIndex &srcIndex) const;
TestResultModel *m_sourceModel;
- QSet<Result::Type> m_enabled;
+ QSet<ResultType> m_enabled;
};
} // namespace Internal
diff --git a/src/plugins/autotest/testresultspane.cpp b/src/plugins/autotest/testresultspane.cpp
index 24d2ff0383..468cc9e32c 100644
--- a/src/plugins/autotest/testresultspane.cpp
+++ b/src/plugins/autotest/testresultspane.cpp
@@ -157,6 +157,8 @@ TestResultsPane::TestResultsPane(QObject *parent) :
this, &TestResultsPane::onTestRunFinished);
connect(TestRunner::instance(), &TestRunner::testResultReady,
this, &TestResultsPane::addTestResult);
+ connect(TestRunner::instance(), &TestRunner::hadDisabledTests,
+ m_model, &TestResultModel::raiseDisabledTests);
}
void TestResultsPane::createToolButtons()
@@ -192,7 +194,6 @@ void TestResultsPane::createToolButtons()
m_filterButton->setIcon(Utils::Icons::FILTER.icon());
m_filterButton->setToolTip(tr("Filter Test Results"));
m_filterButton->setProperty("noArrow", true);
- m_filterButton->setAutoRaise(true);
m_filterButton->setPopupMode(QToolButton::InstantPopup);
m_filterMenu = new QMenu(m_filterButton);
initializeFilterMenu();
@@ -228,9 +229,9 @@ void TestResultsPane::addTestResult(const TestResultPtr &result)
m_atEnd = scrollBar ? scrollBar->value() == scrollBar->maximum() : true;
m_model->addTestResult(result, m_expandCollapse->isChecked());
- setIconBadgeNumber(m_model->resultTypeCount(Result::Fail)
- + m_model->resultTypeCount(Result::MessageFatal)
- + m_model->resultTypeCount(Result::UnexpectedPass));
+ setIconBadgeNumber(m_model->resultTypeCount(ResultType::Fail)
+ + m_model->resultTypeCount(ResultType::MessageFatal)
+ + m_model->resultTypeCount(ResultType::UnexpectedPass));
flash();
navigateStateChanged();
}
@@ -423,24 +424,24 @@ void TestResultsPane::initializeFilterMenu()
const bool omitIntern = AutotestPlugin::settings()->omitInternalMssg;
// FilterModel has all messages enabled by default
if (omitIntern)
- m_filterModel->toggleTestResultType(Result::MessageInternal);
-
- QMap<Result::Type, QString> textAndType;
- textAndType.insert(Result::Pass, tr("Pass"));
- textAndType.insert(Result::Fail, tr("Fail"));
- textAndType.insert(Result::ExpectedFail, tr("Expected Fail"));
- textAndType.insert(Result::UnexpectedPass, tr("Unexpected Pass"));
- textAndType.insert(Result::Skip, tr("Skip"));
- textAndType.insert(Result::Benchmark, tr("Benchmarks"));
- textAndType.insert(Result::MessageDebug, tr("Debug Messages"));
- textAndType.insert(Result::MessageWarn, tr("Warning Messages"));
- textAndType.insert(Result::MessageInternal, tr("Internal Messages"));
- for (Result::Type result : textAndType.keys()) {
+ m_filterModel->toggleTestResultType(ResultType::MessageInternal);
+
+ QMap<ResultType, QString> textAndType;
+ textAndType.insert(ResultType::Pass, tr("Pass"));
+ textAndType.insert(ResultType::Fail, tr("Fail"));
+ textAndType.insert(ResultType::ExpectedFail, tr("Expected Fail"));
+ textAndType.insert(ResultType::UnexpectedPass, tr("Unexpected Pass"));
+ textAndType.insert(ResultType::Skip, tr("Skip"));
+ textAndType.insert(ResultType::Benchmark, tr("Benchmarks"));
+ textAndType.insert(ResultType::MessageDebug, tr("Debug Messages"));
+ textAndType.insert(ResultType::MessageWarn, tr("Warning Messages"));
+ textAndType.insert(ResultType::MessageInternal, tr("Internal Messages"));
+ for (ResultType result : textAndType.keys()) {
QAction *action = new QAction(m_filterMenu);
action->setText(textAndType.value(result));
action->setCheckable(true);
- action->setChecked(result != Result::MessageInternal || !omitIntern);
- action->setData(result);
+ action->setChecked(result != ResultType::MessageInternal || !omitIntern);
+ action->setData(int(result));
m_filterMenu->addAction(action);
}
m_filterMenu->addSeparator();
@@ -457,26 +458,26 @@ void TestResultsPane::updateSummaryLabel()
QString labelText = QString("<p>");
labelText.append(tr("Test summary"));
labelText.append(":&nbsp;&nbsp; ");
- int count = m_model->resultTypeCount(Result::Pass);
+ int count = m_model->resultTypeCount(ResultType::Pass);
labelText += QString::number(count) + ' ' + tr("passes");
- count = m_model->resultTypeCount(Result::Fail);
+ count = m_model->resultTypeCount(ResultType::Fail);
labelText += ", " + QString::number(count) + ' ' + tr("fails");
- count = m_model->resultTypeCount(Result::UnexpectedPass);
+ count = m_model->resultTypeCount(ResultType::UnexpectedPass);
if (count)
labelText += ", " + QString::number(count) + ' ' + tr("unexpected passes");
- count = m_model->resultTypeCount(Result::ExpectedFail);
+ count = m_model->resultTypeCount(ResultType::ExpectedFail);
if (count)
labelText += ", " + QString::number(count) + ' ' + tr("expected fails");
- count = m_model->resultTypeCount(Result::MessageFatal);
+ count = m_model->resultTypeCount(ResultType::MessageFatal);
if (count)
labelText += ", " + QString::number(count) + ' ' + tr("fatals");
- count = m_model->resultTypeCount(Result::BlacklistedFail)
- + m_model->resultTypeCount(Result::BlacklistedXFail)
- + m_model->resultTypeCount(Result::BlacklistedPass)
- + m_model->resultTypeCount(Result::BlacklistedXPass);
+ count = m_model->resultTypeCount(ResultType::BlacklistedFail)
+ + m_model->resultTypeCount(ResultType::BlacklistedXFail)
+ + m_model->resultTypeCount(ResultType::BlacklistedPass)
+ + m_model->resultTypeCount(ResultType::BlacklistedXPass);
if (count)
labelText += ", " + QString::number(count) + ' ' + tr("blacklisted");
- count = m_model->resultTypeCount(Result::Skip);
+ count = m_model->resultTypeCount(ResultType::Skip);
if (count)
labelText += ", " + QString::number(count) + ' ' + tr("skipped");
count = m_model->disabledTests();
@@ -509,6 +510,13 @@ void TestResultsPane::onTestRunStarted()
m_summaryWidget->setVisible(false);
}
+static bool hasFailedTests(const TestResultModel *model)
+{
+ return (model->resultTypeCount(ResultType::Fail) > 0
+ || model->resultTypeCount(ResultType::MessageFatal) > 0
+ || model->resultTypeCount(ResultType::UnexpectedPass) > 0);
+}
+
void TestResultsPane::onTestRunFinished()
{
m_testRunning = false;
@@ -520,8 +528,10 @@ void TestResultsPane::onTestRunFinished()
m_model->removeCurrentTestMessage();
disconnect(m_treeView->verticalScrollBar(), &QScrollBar::rangeChanged,
this, &TestResultsPane::onScrollBarRangeChanged);
- if (!m_treeView->isVisible())
+ if (AutotestPlugin::settings()->popupOnFinish
+ && (!AutotestPlugin::settings()->popupOnFail || hasFailedTests(m_model))) {
popup(Core::IOutputPane::NoModeSwitch);
+ }
createMarks();
}
@@ -637,7 +647,8 @@ QString TestResultsPane::getWholeOutput(const QModelIndex &parent)
QModelIndex current = m_model->index(row, 0, parent);
const TestResult *result = m_model->testResult(current);
QTC_ASSERT(result, continue);
- output.append(TestResult::resultToString(result->result())).append('\t');
+ if (auto item = m_model->itemForIndex(current))
+ output.append(item->resultString()).append('\t');
output.append(result->outputString(true)).append('\n');
output.append(getWholeOutput(current));
}
@@ -647,8 +658,8 @@ QString TestResultsPane::getWholeOutput(const QModelIndex &parent)
void TestResultsPane::createMarks(const QModelIndex &parent)
{
const TestResult *parentResult = m_model->testResult(parent);
- Result::Type parentType = parentResult ? parentResult->result() : Result::Invalid;
- const QVector<Result::Type> interested{Result::Fail, Result::UnexpectedPass};
+ ResultType parentType = parentResult ? parentResult->result() : ResultType::Invalid;
+ const QVector<ResultType> interested{ResultType::Fail, ResultType::UnexpectedPass};
for (int row = 0, count = m_model->rowCount(parent); row < count; ++row) {
const QModelIndex index = m_model->index(row, 0, parent);
const TestResult *result = m_model->testResult(index);
@@ -657,10 +668,10 @@ void TestResultsPane::createMarks(const QModelIndex &parent)
if (m_model->hasChildren(index))
createMarks(index);
- bool isLocationItem = result->result() == Result::MessageLocation;
+ bool isLocationItem = result->result() == ResultType::MessageLocation;
if (interested.contains(result->result())
|| (isLocationItem && interested.contains(parentType))) {
- const Utils::FileName fileName = Utils::FileName::fromString(result->fileName());
+ const Utils::FilePath fileName = Utils::FilePath::fromString(result->fileName());
TestEditorMark *mark = new TestEditorMark(index, fileName, result->line());
mark->setIcon(index.data(Qt::DecorationRole).value<QIcon>());
mark->setColor(Utils::Theme::OutputPanes_TestFailTextColor);
diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp
index 6792b96cb3..cf432870e3 100644
--- a/src/plugins/autotest/testrunner.cpp
+++ b/src/plugins/autotest/testrunner.cpp
@@ -89,8 +89,7 @@ TestRunner::TestRunner(QObject *parent) :
connect(&m_futureWatcher, &QFutureWatcher<TestResultPtr>::canceled,
this, [this]() {
cancelCurrent(UserCanceled);
- emit testResultReady(TestResultPtr(new FaultyTestResult(
- Result::MessageFatal, tr("Test run canceled by user."))));
+ reportResult(ResultType::MessageFatal, tr("Test run canceled by user."));
});
}
@@ -171,8 +170,8 @@ void TestRunner::scheduleNext()
QString commandFilePath = m_currentConfig->executableFilePath();
if (commandFilePath.isEmpty()) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
- tr("Executable path is empty. (%1)").arg(m_currentConfig->displayName()))));
+ reportResult(ResultType::MessageFatal,
+ tr("Executable path is empty. (%1)").arg(m_currentConfig->displayName()));
delete m_currentConfig;
m_currentConfig = nullptr;
if (m_selectedTests.isEmpty())
@@ -200,8 +199,7 @@ void TestRunner::scheduleNext()
m_currentProcess->setArguments(m_currentConfig->argumentsForTestRunner(&omitted));
if (!omitted.isEmpty()) {
const QString &details = constructOmittedDetailsString(omitted);
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
- details.arg(m_currentConfig->displayName()))));
+ reportResult(ResultType::MessageWarn, details.arg(m_currentConfig->displayName()));
}
m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory());
const Utils::Environment &original = m_currentConfig->environment();
@@ -213,21 +211,20 @@ void TestRunner::scheduleNext()
if (!removedVariables.isEmpty()) {
const QString &details = constructOmittedVariablesDetailsString(removedVariables)
.arg(m_currentConfig->displayName());
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn, details)));
+ reportResult(ResultType::MessageWarn, details);
}
m_currentProcess->setProcessEnvironment(environment.toProcessEnvironment());
- connect(m_currentProcess,
- static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
+ connect(m_currentProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &TestRunner::onProcessFinished);
const int timeout = AutotestPlugin::settings()->timeout;
QTimer::singleShot(timeout, m_currentProcess, [this]() { cancelCurrent(Timeout); });
m_currentProcess->start();
if (!m_currentProcess->waitForStarted()) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
+ reportResult(ResultType::MessageFatal,
tr("Failed to start test for project \"%1\".").arg(m_currentConfig->displayName())
- + processInformation(m_currentProcess) + rcInfo(m_currentConfig))));
+ + processInformation(m_currentProcess) + rcInfo(m_currentConfig));
}
}
@@ -238,14 +235,10 @@ void TestRunner::cancelCurrent(TestRunner::CancelReason reason)
if (m_fakeFutureInterface)
m_fakeFutureInterface->reportCanceled();
- auto reportResult = [this](Result::Type type, const QString &detail){
- emit testResultReady(TestResultPtr(new FaultyTestResult(type, detail)));
- };
-
if (reason == KitChanged)
- reportResult(Result::MessageWarn, tr("Current kit has changed. Canceling test run."));
+ reportResult(ResultType::MessageWarn, tr("Current kit has changed. Canceling test run."));
else if (reason == Timeout)
- reportResult(Result::MessageFatal, tr("Test case canceled due to timeout.\nMaybe raise the timeout?"));
+ reportResult(ResultType::MessageFatal, tr("Test case canceled due to timeout.\nMaybe raise the timeout?"));
// if user or timeout cancels the current run ensure to kill the running process
if (m_currentProcess && m_currentProcess->state() != QProcess::NotRunning) {
@@ -263,17 +256,23 @@ void TestRunner::onProcessFinished()
if (!m_fakeFutureInterface->isCanceled()) {
if (m_currentProcess->exitStatus() == QProcess::CrashExit) {
m_currentOutputReader->reportCrash();
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
+ reportResult(ResultType::MessageFatal,
tr("Test for project \"%1\" crashed.").arg(m_currentConfig->displayName())
- + processInformation(m_currentProcess) + rcInfo(m_currentConfig))));
+ + processInformation(m_currentProcess) + rcInfo(m_currentConfig));
} else if (!m_currentOutputReader->hadValidOutput()) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
+ reportResult(ResultType::MessageFatal,
tr("Test for project \"%1\" did not produce any expected output.")
.arg(m_currentConfig->displayName()) + processInformation(m_currentProcess)
- + rcInfo(m_currentConfig))));
+ + rcInfo(m_currentConfig));
}
}
}
+ const int disabled = m_currentOutputReader->disabledTests();
+ if (disabled > 0)
+ emit hadDisabledTests(disabled);
+ if (m_currentOutputReader->hasSummary())
+ emit reportSummary(m_currentOutputReader->id(), m_currentOutputReader->summary());
+
resetInternalPointers();
if (!m_fakeFutureInterface) {
@@ -315,18 +314,17 @@ void TestRunner::prepareToRunTests(TestRunMode mode)
TestResultsPane::instance()->clearContents();
if (m_selectedTests.empty()) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
- tr("No tests selected. Canceling test run."))));
+ reportResult(ResultType::MessageWarn, tr("No tests selected. Canceling test run."));
onFinished();
return;
}
ProjectExplorer::Project *project = m_selectedTests.at(0)->project();
if (!project) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
+ reportResult(ResultType::MessageWarn,
tr("Project is null. Canceling test run.\n"
- "Only desktop kits are supported. Make sure the "
- "currently active kit is a desktop kit."))));
+ "Only desktop kits are supported. Make sure the "
+ "currently active kit is a desktop kit."));
onFinished();
return;
}
@@ -340,8 +338,8 @@ void TestRunner::prepareToRunTests(TestRunMode mode)
} else if (project->hasActiveBuildSettings()) {
buildProject(project);
} else {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
- tr("Project is not configured. Canceling test run."))));
+ reportResult(ResultType::MessageFatal,
+ tr("Project is not configured. Canceling test run."));
onFinished();
}
}
@@ -414,13 +412,12 @@ int TestRunner::precheckTestConfigurations()
"This might cause trouble during execution.\n"
"(deduced from \"%2\")");
message = message.arg(config->displayName()).arg(config->runConfigDisplayName());
- emit testResultReady(
- TestResultPtr(new FaultyTestResult(Result::MessageWarn, message)));
+ reportResult(ResultType::MessageWarn, message);
}
} else {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
- tr("Project is null for \"%1\". Removing from test run.\n"
- "Check the test environment.").arg(config->displayName()))));
+ reportResult(ResultType::MessageWarn,
+ tr("Project is null for \"%1\". Removing from test run.\n"
+ "Check the test environment.").arg(config->displayName()));
}
}
return testCaseCount;
@@ -450,7 +447,7 @@ void TestRunner::runTests()
QString mssg = projectChanged ? tr("Startup project has changed. Canceling test run.")
: tr("No test cases left for execution. Canceling test run.");
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn, mssg)));
+ reportResult(ResultType::MessageWarn, mssg);
onFinished();
return;
}
@@ -465,6 +462,8 @@ void TestRunner::runTests()
m_futureWatcher.setFuture(future);
Core::ProgressManager::addTask(future, tr("Running Tests"), Autotest::Constants::TASK_INDEX);
+ if (AutotestPlugin::settings()->popupOnStart)
+ AutotestPlugin::popupResultsPane();
scheduleNext();
}
@@ -514,8 +513,8 @@ void TestRunner::debugTests()
TestConfiguration *config = m_selectedTests.first();
config->completeTestInformation(TestRunMode::Debug);
if (!config->project()) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
- TestRunner::tr("Startup project has changed. Canceling test run."))));
+ reportResult(ResultType::MessageWarn,
+ tr("Startup project has changed. Canceling test run."));
onFinished();
return;
}
@@ -525,28 +524,26 @@ void TestRunner::debugTests()
}
if (!config->runConfiguration()) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
- TestRunner::tr("Failed to get run configuration."))));
+ reportResult(ResultType::MessageFatal, tr("Failed to get run configuration."));
onFinished();
return;
}
const QString &commandFilePath = config->executableFilePath();
if (commandFilePath.isEmpty()) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
- TestRunner::tr("Could not find command \"%1\". (%2)")
- .arg(config->executableFilePath())
- .arg(config->displayName()))));
+ reportResult(ResultType::MessageFatal, tr("Could not find command \"%1\". (%2)")
+ .arg(config->executableFilePath())
+ .arg(config->displayName()));
onFinished();
return;
}
QString errorMessage;
- auto runControl = new ProjectExplorer::RunControl(config->runConfiguration(),
- ProjectExplorer::Constants::DEBUG_RUN_MODE);
+ auto runControl = new ProjectExplorer::RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE);
+ runControl->setRunConfiguration(config->runConfiguration());
if (!runControl) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
- TestRunner::tr("Failed to create run configuration.\n%1").arg(errorMessage))));
+ reportResult(ResultType::MessageFatal,
+ tr("Failed to create run configuration.\n%1").arg(errorMessage));
onFinished();
return;
}
@@ -559,8 +556,7 @@ void TestRunner::debugTests()
inferior.commandLineArguments = Utils::QtcProcess::joinArgs(args);
if (!omitted.isEmpty()) {
const QString &details = constructOmittedDetailsString(omitted);
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
- details.arg(config->displayName()))));
+ reportResult(ResultType::MessageWarn, details.arg(config->displayName()));
}
Utils::Environment original(inferior.environment);
inferior.environment = config->filteredEnvironment(original);
@@ -571,7 +567,7 @@ void TestRunner::debugTests()
if (!removedVariables.isEmpty()) {
const QString &details = constructOmittedVariablesDetailsString(removedVariables)
.arg(config->displayName());
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn, details)));
+ reportResult(ResultType::MessageWarn, details);
}
auto debugger = new Debugger::DebuggerRunTool(runControl);
debugger->setInferior(inferior);
@@ -579,9 +575,9 @@ void TestRunner::debugTests()
bool useOutputProcessor = true;
if (ProjectExplorer::Target *targ = config->project()->activeTarget()) {
- if (Debugger::DebuggerKitInformation::engineType(targ->kit()) == Debugger::CdbEngineType) {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageWarn,
- TestRunner::tr("Unable to display test results when using CDB."))));
+ if (Debugger::DebuggerKitAspect::engineType(targ->kit()) == Debugger::CdbEngineType) {
+ reportResult(ResultType::MessageWarn,
+ tr("Unable to display test results when using CDB."));
useOutputProcessor = false;
}
}
@@ -596,9 +592,8 @@ void TestRunner::debugTests()
outputreader->setId(inferior.executable);
connect(outputreader, &TestOutputReader::newOutputAvailable,
TestResultsPane::instance(), &TestResultsPane::addOutput);
- connect(runControl, &ProjectExplorer::RunControl::appendMessageRequested,
- this, [outputreader]
- (ProjectExplorer::RunControl *, const QString &msg, Utils::OutputFormat format) {
+ connect(runControl, &ProjectExplorer::RunControl::appendMessage,
+ this, [outputreader](const QString &msg, Utils::OutputFormat format) {
processOutput(outputreader, msg, format);
});
@@ -611,6 +606,8 @@ void TestRunner::debugTests()
connect(runControl, &ProjectExplorer::RunControl::stopped, this, &TestRunner::onFinished);
ProjectExplorer::ProjectExplorerPlugin::startRunControl(runControl);
+ if (useOutputProcessor && AutotestPlugin::settings()->popupOnStart)
+ AutotestPlugin::popupResultsPane();
}
void TestRunner::runOrDebugTests()
@@ -654,8 +651,7 @@ void TestRunner::buildFinished(bool success)
else if (m_executingTests)
onFinished();
} else {
- emit testResultReady(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
- tr("Build failed. Canceling test run."))));
+ reportResult(ResultType::MessageFatal, tr("Build failed. Canceling test run."));
onFinished();
}
}
@@ -673,6 +669,14 @@ void TestRunner::onFinished()
emit testRunFinished();
}
+void TestRunner::reportResult(ResultType type, const QString &description)
+{
+ TestResultPtr result(new TestResult);
+ result->setResult(type);
+ result->setDescription(description);
+ emit testResultReady(result);
+}
+
/*************************************************************************************************/
static QFrame *createLine(QWidget *parent)
diff --git a/src/plugins/autotest/testrunner.h b/src/plugins/autotest/testrunner.h
index b56d797401..5628a6d29e 100644
--- a/src/plugins/autotest/testrunner.h
+++ b/src/plugins/autotest/testrunner.h
@@ -70,6 +70,8 @@ signals:
void testRunFinished();
void requestStopTestRun();
void testResultReady(const TestResultPtr &result);
+ void hadDisabledTests(int disabled);
+ void reportSummary(const QString &id, const QHash<ResultType, int> &summary);
private:
void buildProject(ProjectExplorer::Project *project);
@@ -85,6 +87,7 @@ private:
void runTests();
void debugTests();
void runOrDebugTests();
+ void reportResult(ResultType type, const QString &description);
explicit TestRunner(QObject *parent = nullptr);
QFutureWatcher<TestResultPtr> m_futureWatcher;
diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp
index c825ea5573..ddb4f49e81 100644
--- a/src/plugins/autotest/testsettings.cpp
+++ b/src/plugins/autotest/testsettings.cpp
@@ -39,10 +39,11 @@ static const char omitInternalKey[] = "OmitInternal";
static const char omitRunConfigWarnKey[] = "OmitRCWarnings";
static const char limitResultOutputKey[] = "LimitResultOutput";
static const char autoScrollKey[] = "AutoScrollResults";
-static const char filterScanKey[] = "FilterScan";
-static const char filtersKey[] = "WhiteListFilters";
static const char processArgsKey[] = "ProcessArgs";
static const char displayApplicationKey[] = "DisplayApp";
+static const char popupOnStartKey[] = "PopupOnStart";
+static const char popupOnFinishKey[] = "PopupOnFinish";
+static const char popupOnFailKey[] = "PopupOnFail";
static const char groupSuffix[] = ".group";
constexpr int defaultTimeout = 60000;
@@ -62,8 +63,9 @@ void TestSettings::toSettings(QSettings *s) const
s->setValue(autoScrollKey, autoScroll);
s->setValue(processArgsKey, processArgs);
s->setValue(displayApplicationKey, displayApplication);
- s->setValue(filterScanKey, filterScan);
- s->setValue(filtersKey, whiteListFilters);
+ s->setValue(popupOnStartKey, popupOnStart);
+ s->setValue(popupOnFinishKey, popupOnFinish);
+ s->setValue(popupOnFailKey, popupOnFail);
// store frameworks and their current active and grouping state
for (const Core::Id &id : frameworks.keys()) {
s->setValue(QLatin1String(id.name()), frameworks.value(id));
@@ -82,8 +84,9 @@ void TestSettings::fromSettings(QSettings *s)
autoScroll = s->value(autoScrollKey, true).toBool();
processArgs = s->value(processArgsKey, false).toBool();
displayApplication = s->value(displayApplicationKey, false).toBool();
- filterScan = s->value(filterScanKey, false).toBool();
- whiteListFilters = s->value(filtersKey, QStringList()).toStringList();
+ popupOnStart = s->value(popupOnStartKey, true).toBool();
+ popupOnFinish = s->value(popupOnFinishKey, true).toBool();
+ popupOnFail = s->value(popupOnFailKey, false).toBool();
// try to get settings for registered frameworks
TestFrameworkManager *frameworkManager = TestFrameworkManager::instance();
const QList<Core::Id> &registered = frameworkManager->registeredFrameworkIds();
diff --git a/src/plugins/autotest/testsettings.h b/src/plugins/autotest/testsettings.h
index 6eff083e59..92c4ef9933 100644
--- a/src/plugins/autotest/testsettings.h
+++ b/src/plugins/autotest/testsettings.h
@@ -47,12 +47,13 @@ struct TestSettings
bool omitRunConfigWarn = false;
bool limitResultOutput = true;
bool autoScroll = true;
- bool filterScan = false;
bool processArgs = false;
bool displayApplication = false;
+ bool popupOnStart = true;
+ bool popupOnFinish = true;
+ bool popupOnFail = false;
QHash<Core::Id, bool> frameworks;
QHash<Core::Id, bool> frameworksGrouping;
- QStringList whiteListFilters;
};
} // namespace Internal
diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp
index e2bf15ae6c..169bab7320 100644
--- a/src/plugins/autotest/testsettingspage.cpp
+++ b/src/plugins/autotest/testsettingspage.cpp
@@ -32,90 +32,12 @@
#include "autotestplugin.h"
#include <coreplugin/icore.h>
-#include <utils/fancylineedit.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
-#include <QDialog>
-#include <QDialogButtonBox>
-#include <QRegExp>
-
namespace Autotest {
namespace Internal {
-class TestFilterDialog : public QDialog
-{
-public:
- explicit TestFilterDialog(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr);
- QString filterPath() const;
- void setDetailsText(const QString &details) { m_details->setText(details); }
- void setDefaultFilterPath(const QString &defaultPath);
-private:
- static bool validate(Utils::FancyLineEdit *edit, QString * /*errormessage*/);
- QLabel *m_details;
- Utils::FancyLineEdit *m_lineEdit;
- QString m_defaultPath;
-};
-
-TestFilterDialog::TestFilterDialog(QWidget *parent, Qt::WindowFlags f)
- : QDialog(parent, f),
- m_details(new QLabel),
- m_lineEdit(new Utils::FancyLineEdit)
-{
- setModal(true);
- auto layout = new QVBoxLayout(this);
- layout->setSizeConstraint(QLayout::SetFixedSize);
- layout->addWidget(m_details);
- m_lineEdit->setValidationFunction(&validate);
- layout->addWidget(m_lineEdit);
- auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
- auto okButton = buttonBox->button(QDialogButtonBox::Ok);
- auto cancelButton = buttonBox->button(QDialogButtonBox::Cancel);
- okButton->setEnabled(false);
- layout->addWidget(buttonBox);
- setLayout(layout);
- connect(m_lineEdit, &Utils::FancyLineEdit::validChanged, okButton, &QPushButton::setEnabled);
- connect(okButton, &QPushButton::clicked, this, &QDialog::accept);
- connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
-}
-
-QString TestFilterDialog::filterPath() const
-{
- static const QRegExp repetition("//+");
- QString path = m_lineEdit->isValid() ? m_lineEdit->text() : m_defaultPath;
- path.replace('\\', '/'); // turn windows separators into forward slashes
- path.replace(repetition, "/"); // avoid duplicated separators
- if (!path.startsWith('/'))
- path.prepend('/');
- if (!path.endsWith('/'))
- path.append('/');
- if (path.length() <= 2) // after surrounding with '/' this should be > 2 if valid
- return QString(); // empty string marks invalid filter
- return path;
-}
-
-void TestFilterDialog::setDefaultFilterPath(const QString &defaultPath)
-{
- m_lineEdit->setText(defaultPath);
- if (m_lineEdit->isValid())
- m_defaultPath = defaultPath;
- else
- m_lineEdit->setText(m_defaultPath);
-}
-
-bool TestFilterDialog::validate(Utils::FancyLineEdit *edit, QString *)
-{
- if (!edit)
- return false;
- const QString &value = edit->text();
- if (value.isEmpty())
- return false;
- // should we distinguish between Windows and UNIX?
- static const QRegExp valid("(\\|/)?([^?*:;\"\'|<>\t\b]+(\\|/)?)+");
- return valid.exactMatch(value);
-}
-/**************************************************************************************************/
-
TestSettingsWidget::TestSettingsWidget(QWidget *parent)
: QWidget(parent)
{
@@ -129,19 +51,10 @@ TestSettingsWidget::TestSettingsWidget(QWidget *parent)
"having at least one active test framework."));
connect(m_ui.frameworkTreeWidget, &QTreeWidget::itemChanged,
this, &TestSettingsWidget::onFrameworkItemChanged);
- connect(m_ui.addFilter, &QPushButton::clicked, this, &TestSettingsWidget::onAddFilterClicked);
- connect(m_ui.editFilter, &QPushButton::clicked, this, &TestSettingsWidget::onEditFilterClicked);
- connect(m_ui.filterTreeWidget, &QTreeWidget::activated,
- this, &TestSettingsWidget::onEditFilterClicked);
- connect(m_ui.removeFilter, &QPushButton::clicked,
- this, &TestSettingsWidget::onRemoveFilterClicked);
- connect(m_ui.filterTreeWidget, &QTreeWidget::itemSelectionChanged, [this] () {
- const bool enable = m_ui.filterTreeWidget->selectionModel()->hasSelection();
- m_ui.editFilter->setEnabled(enable);
- m_ui.removeFilter->setEnabled(enable);
- });
connect(m_ui.resetChoicesButton, &QPushButton::clicked,
this, [] { AutotestPlugin::clearChoiceCache(); });
+ connect(m_ui.openResultsOnFinishCB, &QCheckBox::toggled,
+ m_ui.openResultsOnFailCB, &QCheckBox::setEnabled);
}
void TestSettingsWidget::setSettings(const TestSettings &settings)
@@ -153,9 +66,10 @@ void TestSettingsWidget::setSettings(const TestSettings &settings)
m_ui.autoScrollCB->setChecked(settings.autoScroll);
m_ui.processArgsCB->setChecked(settings.processArgs);
m_ui.displayAppCB->setChecked(settings.displayApplication);
- m_ui.filterGroupBox->setChecked(settings.filterScan);
+ m_ui.openResultsOnStartCB->setChecked(settings.popupOnStart);
+ m_ui.openResultsOnFinishCB->setChecked(settings.popupOnFinish);
+ m_ui.openResultsOnFailCB->setChecked(settings.popupOnFail);
populateFrameworksListWidget(settings.frameworks);
- populateFiltersWidget(settings.whiteListFilters);
}
TestSettings TestSettingsWidget::settings() const
@@ -168,9 +82,10 @@ TestSettings TestSettingsWidget::settings() const
result.autoScroll = m_ui.autoScrollCB->isChecked();
result.processArgs = m_ui.processArgsCB->isChecked();
result.displayApplication = m_ui.displayAppCB->isChecked();
- result.filterScan = m_ui.filterGroupBox->isChecked();
+ result.popupOnStart = m_ui.openResultsOnStartCB->isChecked();
+ result.popupOnFinish = m_ui.openResultsOnFinishCB->isChecked();
+ result.popupOnFail = m_ui.openResultsOnFailCB->isChecked();
frameworkSettings(result);
- result.whiteListFilters = filters();
return result;
}
@@ -196,12 +111,6 @@ void TestSettingsWidget::populateFrameworksListWidget(const QHash<Core::Id, bool
}
}
-void TestSettingsWidget::populateFiltersWidget(const QStringList &filters)
-{
- for (const QString &filter : filters)
- new QTreeWidgetItem(m_ui.filterTreeWidget, {filter} );
-}
-
void TestSettingsWidget::frameworkSettings(TestSettings &settings) const
{
const QAbstractItemModel *model = m_ui.frameworkTreeWidget->model();
@@ -216,16 +125,6 @@ void TestSettingsWidget::frameworkSettings(TestSettings &settings) const
}
}
-QStringList TestSettingsWidget::filters() const
-{
- QStringList result;
- if (QAbstractItemModel *model = m_ui.filterTreeWidget->model()) {
- for (int row = 0, count = model->rowCount(); row < count; ++row)
- result.append(model->index(row, 0).data().toString());
- }
- return result;
-}
-
void TestSettingsWidget::onFrameworkItemChanged()
{
if (QAbstractItemModel *model = m_ui.frameworkTreeWidget->model()) {
@@ -241,45 +140,6 @@ void TestSettingsWidget::onFrameworkItemChanged()
m_ui.frameworksWarnIcon->setVisible(true);
}
-void TestSettingsWidget::onAddFilterClicked()
-{
- TestFilterDialog dialog;
- dialog.setWindowTitle(tr("Add Filter"));
- dialog.setDetailsText("<p>" + tr("Specify a filter expression to be added to the list of filters."
- "<br/>Wildcards are not supported.") + "</p>");
- if (dialog.exec() == QDialog::Accepted) {
- const QString &filter = dialog.filterPath();
- if (!filter.isEmpty())
- new QTreeWidgetItem(m_ui.filterTreeWidget, {filter} );
- }
-}
-
-void TestSettingsWidget::onEditFilterClicked()
-{
- const QList<QTreeWidgetItem *> &selected = m_ui.filterTreeWidget->selectedItems();
- QTC_ASSERT(selected.size() == 1, return);
- const QString &oldFilter = selected.first()->data(0, Qt::DisplayRole).toString();
-
- TestFilterDialog dialog;
- dialog.setWindowTitle(tr("Edit Filter"));
- dialog.setDetailsText("<p>" + tr("Specify a filter expression that will replace \"%1\"."
- "<br/>Wildcards are not supported.").arg(oldFilter) + "</p>");
- dialog.setDefaultFilterPath(oldFilter);
- if (dialog.exec() == QDialog::Accepted) {
- const QString &edited = dialog.filterPath();
- if (!edited.isEmpty() && edited != oldFilter)
- selected.first()->setData(0, Qt::DisplayRole, edited);
- }
-}
-
-void TestSettingsWidget::onRemoveFilterClicked()
-{
- const QList<QTreeWidgetItem *> &selected = m_ui.filterTreeWidget->selectedItems();
- QTC_ASSERT(selected.size() == 1, return);
- m_ui.filterTreeWidget->removeItemWidget(selected.first(), 0);
- delete selected.first();
-}
-
TestSettingsPage::TestSettingsPage(const QSharedPointer<TestSettings> &settings)
: m_settings(settings)
{
@@ -306,8 +166,6 @@ void TestSettingsPage::apply()
return;
const TestSettings newSettings = m_widget->settings();
bool frameworkSyncNecessary = newSettings.frameworks != m_settings->frameworks;
- bool forceReparse = newSettings.filterScan != m_settings->filterScan ||
- newSettings.whiteListFilters.toSet() != m_settings->whiteListFilters.toSet();
const QList<Core::Id> changedIds = Utils::filtered(newSettings.frameworksGrouping.keys(),
[newSettings, this] (const Core::Id &id) {
return newSettings.frameworksGrouping[id] != m_settings->frameworksGrouping[id];
@@ -318,8 +176,6 @@ void TestSettingsPage::apply()
frameworkManager->activateFrameworksFromSettings(m_settings);
if (frameworkSyncNecessary)
TestTreeModel::instance()->syncTestFrameworks();
- else if (forceReparse)
- TestTreeModel::instance()->parser()->emitUpdateTestTree();
else if (!changedIds.isEmpty())
TestTreeModel::instance()->rebuild(changedIds);
}
diff --git a/src/plugins/autotest/testsettingspage.h b/src/plugins/autotest/testsettingspage.h
index 2b1216c9eb..a100500476 100644
--- a/src/plugins/autotest/testsettingspage.h
+++ b/src/plugins/autotest/testsettingspage.h
@@ -47,13 +47,8 @@ public:
private:
void populateFrameworksListWidget(const QHash<Core::Id, bool> &frameworks);
- void populateFiltersWidget(const QStringList &filters);
void frameworkSettings(TestSettings &settings) const;
- QStringList filters() const;
void onFrameworkItemChanged();
- void onAddFilterClicked();
- void onEditFilterClicked();
- void onRemoveFilterClicked();
Ui::TestSettingsPage m_ui;
};
diff --git a/src/plugins/autotest/testsettingspage.ui b/src/plugins/autotest/testsettingspage.ui
index dbdf49842a..cb65055bc3 100644
--- a/src/plugins/autotest/testsettingspage.ui
+++ b/src/plugins/autotest/testsettingspage.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>585</width>
- <height>458</height>
+ <width>586</width>
+ <height>429</height>
</rect>
</property>
<property name="windowTitle">
@@ -61,6 +61,59 @@
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="openResultsOnStartCB">
+ <property name="toolTip">
+ <string>Opens the test results pane automatically when tests are started.</string>
+ </property>
+ <property name="text">
+ <string>Open results pane when tests start</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="openResultsOnFinishCB">
+ <property name="toolTip">
+ <string>Opens the test result pane automatically when tests are finished.</string>
+ </property>
+ <property name="text">
+ <string>Open results pane when tests finish</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="openResultsOnFailCB">
+ <property name="toolTip">
+ <string>Opens the test result pane only if the test run contains failed, fatal or unexpectedly passed tests.</string>
+ </property>
+ <property name="text">
+ <string>Only for unsuccessful test runs</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
<widget class="QCheckBox" name="autoScrollCB">
<property name="toolTip">
<string>Automatically scrolls down when new items are added and scrollbar is at bottom.</string>
@@ -284,102 +337,6 @@ Warning: this is an experimental feature and might lead to failing to execute th
</layout>
</item>
<item>
- <widget class="QGroupBox" name="filterGroupBox">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="title">
- <string>Global Filters</string>
- </property>
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QTreeWidget" name="filterTreeWidget">
- <property name="toolTip">
- <string>Filters used on directories when scanning for tests.&lt;br/&gt;If filtering is enabled, only directories that match any of the filters will be scanned.</string>
- </property>
- <property name="uniformRowHeights">
- <bool>true</bool>
- </property>
- <property name="headerHidden">
- <bool>true</bool>
- </property>
- <column>
- <property name="text">
- <string notr="true">1</string>
- </property>
- </column>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QPushButton" name="addFilter">
- <property name="text">
- <string>Add...</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="editFilter">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Edit...</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_5">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="removeFilter">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Remove</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_4">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/plugins/autotest/testtreeitem.cpp b/src/plugins/autotest/testtreeitem.cpp
index e1c1debe9c..bc3c4f16be 100644
--- a/src/plugins/autotest/testtreeitem.cpp
+++ b/src/plugins/autotest/testtreeitem.cpp
@@ -47,8 +47,9 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty
switch (m_type) {
case Root:
case GroupNode:
+ case TestSuite:
case TestCase:
- case TestFunctionOrSet:
+ case TestFunction:
m_checked = Qt::Checked;
break;
default:
@@ -62,6 +63,7 @@ static QIcon testTreeIcon(TestTreeItem::Type type)
static QIcon icons[] = {
QIcon(),
Utils::Icons::OPENFILE.icon(),
+ QIcon(":/autotest/images/suite.png"),
Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Class),
Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::SlotPrivate),
QIcon(":/autotest/images/data.png")
@@ -120,16 +122,17 @@ Qt::ItemFlags TestTreeItem::flags(int /*column*/) const
case Root:
case GroupNode:
return Qt::ItemIsEnabled | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
+ case TestSuite:
case TestCase:
return defaultFlags | Qt::ItemIsAutoTristate | Qt::ItemIsUserCheckable;
- case TestFunctionOrSet:
+ case TestFunction:
return defaultFlags | Qt::ItemIsUserCheckable;
default:
return defaultFlags;
}
}
-bool TestTreeItem::modifyTestCaseContent(const TestParseResult *result)
+bool TestTreeItem::modifyTestCaseOrSuiteContent(const TestParseResult *result)
{
bool hasBeenModified = modifyName(result->name);
hasBeenModified |= modifyLineAndColumn(result);
@@ -170,8 +173,9 @@ Qt::CheckState TestTreeItem::checked() const
switch (m_type) {
case Root:
case GroupNode:
+ case TestSuite:
case TestCase:
- case TestFunctionOrSet:
+ case TestFunction:
case TestDataTag:
return m_checked;
default:
@@ -255,7 +259,7 @@ QList<TestConfiguration *> TestTreeItem::getSelectedTestConfigurations() const
return QList<TestConfiguration *>();
}
-QList<TestConfiguration *> TestTreeItem::getTestConfigurationsForFile(const Utils::FileName &) const
+QList<TestConfiguration *> TestTreeItem::getTestConfigurationsForFile(const Utils::FilePath &) const
{
return QList<TestConfiguration *>();
}
@@ -364,9 +368,9 @@ QSet<QString> TestTreeItem::dependingInternalTargets(CppTools::CppModelManager *
bool wasHeader;
const QString correspondingFile
= CppTools::correspondingHeaderOrSource(file, &wasHeader, CppTools::CacheUsage::ReadOnly);
- const Utils::FileNameList dependingFiles = snapshot.filesDependingOn(
+ const Utils::FilePathList dependingFiles = snapshot.filesDependingOn(
wasHeader ? file : correspondingFile);
- for (const Utils::FileName &fn : dependingFiles) {
+ for (const Utils::FilePath &fn : dependingFiles) {
for (const CppTools::ProjectPart::Ptr &part : cppMM->projectPart(fn))
result.insert(part->buildSystemTarget);
}
diff --git a/src/plugins/autotest/testtreeitem.h b/src/plugins/autotest/testtreeitem.h
index 74e6c98d8f..e6d47bb820 100644
--- a/src/plugins/autotest/testtreeitem.h
+++ b/src/plugins/autotest/testtreeitem.h
@@ -42,7 +42,7 @@ namespace {
}
namespace CppTools { class CppModelManager; }
-namespace Utils { class FileName; }
+namespace Utils { class FilePath; }
namespace Autotest {
namespace Internal {
@@ -59,8 +59,9 @@ public:
{
Root,
GroupNode,
+ TestSuite,
TestCase,
- TestFunctionOrSet,
+ TestFunction,
TestDataTag,
TestDataFunction,
TestSpecialFunction
@@ -78,7 +79,7 @@ public:
virtual QVariant data(int column, int role) const override;
virtual bool setData(int column, const QVariant &data, int role) override;
virtual Qt::ItemFlags flags(int column) const override;
- bool modifyTestCaseContent(const TestParseResult *result);
+ bool modifyTestCaseOrSuiteContent(const TestParseResult *result);
bool modifyTestFunctionContent(const TestParseResult *result);
bool modifyDataTagContent(const TestParseResult *result);
bool modifyLineAndColumn(const TestParseResult *result);
@@ -115,7 +116,7 @@ public:
TestConfiguration *asConfiguration(TestRunMode mode) const;
virtual QList<TestConfiguration *> getAllTestConfigurations() const;
virtual QList<TestConfiguration *> getSelectedTestConfigurations() const;
- virtual QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FileName &fileName) const;
+ virtual QList<TestConfiguration *> getTestConfigurationsForFile(const Utils::FilePath &fileName) const;
virtual bool lessThan(const TestTreeItem *other, SortMode mode) const;
virtual TestTreeItem *find(const TestParseResult *result) = 0;
virtual TestTreeItem *findChild(const TestTreeItem *other) = 0;
@@ -126,6 +127,8 @@ public:
// based on (internal) filters this will be used to filter out sub items (and remove them)
// returns a copy of the item that contains the filtered out children or nullptr
virtual TestTreeItem *applyFilters() { return nullptr; }
+ // decide whether an item should still be added to the treemodel
+ virtual bool shouldBeAddedAfterFiltering() const { return true; }
virtual QSet<QString> internalTargets() const;
protected:
void copyBasicDataFrom(const TestTreeItem *other);
diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp
index 7e4e577812..953e93dc9c 100644
--- a/src/plugins/autotest/testtreemodel.cpp
+++ b/src/plugins/autotest/testtreemodel.cpp
@@ -158,7 +158,7 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const
return result;
}
-QList<TestConfiguration *> TestTreeModel::getTestsForFile(const Utils::FileName &fileName) const
+QList<TestConfiguration *> TestTreeModel::getTestsForFile(const Utils::FilePath &fileName) const
{
QList<TestConfiguration *> result;
for (Utils::TreeItem *frameworkRoot : *rootItem())
@@ -171,14 +171,14 @@ QList<TestTreeItem *> TestTreeModel::testItemsByName(TestTreeItem *root, const Q
QList<TestTreeItem *> result;
root->forFirstLevelChildren([&testName, &result, this](TestTreeItem *node) {
- if (node->type() == TestTreeItem::TestCase) {
+ if (node->type() == TestTreeItem::TestSuite || node->type() == TestTreeItem::TestCase) {
if (node->name() == testName) {
result << node;
- return; // prioritize Tests over TestCases
+ return; // prioritize test suites and cases over test functions
}
TestTreeItem *testCase = node->findFirstLevelChild([&testName](TestTreeItem *it) {
QTC_ASSERT(it, return false);
- return it->type() == TestTreeItem::TestFunctionOrSet && it->name() == testName;
+ return it->type() == TestTreeItem::TestFunction && it->name() == testName;
}); // collect only actual tests, not special functions like init, cleanup etc.
if (testCase)
result << testCase;
@@ -215,7 +215,7 @@ void TestTreeModel::syncTestFrameworks()
void TestTreeModel::filterAndInsert(TestTreeItem *item, TestTreeItem *root, bool groupingEnabled)
{
TestTreeItem *filtered = item->applyFilters();
- if (item->type() != TestTreeItem::TestCase || item->childCount())
+ if (item->shouldBeAddedAfterFiltering())
insertItemInParent(item, root, groupingEnabled);
else // might be that all children have been filtered out
delete item;
@@ -481,24 +481,30 @@ void TestTreeModel::removeTestRootNodes()
#ifdef WITH_TESTS
// we're inside tests - so use some internal knowledge to make testing easier
-TestTreeItem *qtRootNode()
+static TestTreeItem *qtRootNode()
{
return TestFrameworkManager::instance()->rootNodeForTestFramework(
Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtTest"));
}
-TestTreeItem *quickRootNode()
+static TestTreeItem *quickRootNode()
{
return TestFrameworkManager::instance()->rootNodeForTestFramework(
Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("QtQuickTest"));
}
-TestTreeItem *gtestRootNode()
+static TestTreeItem *gtestRootNode()
{
return TestFrameworkManager::instance()->rootNodeForTestFramework(
Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("GTest"));
}
+static TestTreeItem *boostTestRootNode()
+{
+ return TestFrameworkManager::instance()->rootNodeForTestFramework(
+ Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix("Boost"));
+}
+
int TestTreeModel::autoTestsCount() const
{
TestTreeItem *rootNode = qtRootNode();
@@ -570,6 +576,25 @@ QMultiMap<QString, int> TestTreeModel::gtestNamesAndSets() const
}
return result;
}
+
+int TestTreeModel::boostTestNamesCount() const
+{
+ TestTreeItem *rootNode = boostTestRootNode();
+ return rootNode ? rootNode->childCount() : 0;
+}
+
+QMultiMap<QString, int> TestTreeModel::boostTestSuitesAndTests() const
+{
+ QMultiMap<QString, int> result;
+
+ if (TestTreeItem *rootNode = boostTestRootNode()) {
+ rootNode->forFirstLevelChildren([&result](TestTreeItem *child) {
+ result.insert(child->name(), child->childCount());
+ });
+ }
+ return result;
+}
+
#endif
/***************************** Sort/Filter Model **********************************/
diff --git a/src/plugins/autotest/testtreemodel.h b/src/plugins/autotest/testtreemodel.h
index 2945765d47..895a9a582e 100644
--- a/src/plugins/autotest/testtreemodel.h
+++ b/src/plugins/autotest/testtreemodel.h
@@ -56,7 +56,7 @@ public:
bool hasTests() const;
QList<TestConfiguration *> getAllTestCases() const;
QList<TestConfiguration *> getSelectedTests() const;
- QList<TestConfiguration *> getTestsForFile(const Utils::FileName &fileName) const;
+ QList<TestConfiguration *> getTestsForFile(const Utils::FilePath &fileName) const;
QList<TestTreeItem *> testItemsByName(const QString &testName);
void syncTestFrameworks();
void rebuild(const QList<Core::Id> &frameworkIds);
@@ -70,6 +70,8 @@ public:
int dataTagsCount() const;
int gtestNamesCount() const;
QMultiMap<QString, int> gtestNamesAndSets() const;
+ int boostTestNamesCount() const;
+ QMultiMap<QString, int> boostTestSuitesAndTests() const;
#endif
void markAllForRemoval();
diff --git a/src/plugins/autotest/unit_test/simple_boost/simple_boost.pro b/src/plugins/autotest/unit_test/simple_boost/simple_boost.pro
new file mode 100644
index 0000000000..f0f3a156bb
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/simple_boost.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += src tests
diff --git a/src/plugins/autotest/unit_test/simple_boost/simple_boost.qbs b/src/plugins/autotest/unit_test/simple_boost/simple_boost.qbs
new file mode 100644
index 0000000000..413f4f4971
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/simple_boost.qbs
@@ -0,0 +1,5 @@
+import qbs
+Project {
+ name: "SimpleBoost"
+ references: [ "src/src.qbs", "tests/tests.qbs" ]
+}
diff --git a/src/plugins/autotest/unit_test/simple_boost/src/main.cpp b/src/plugins/autotest/unit_test/simple_boost/src/main.cpp
new file mode 100644
index 0000000000..bc90974049
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/src/main.cpp
@@ -0,0 +1,6 @@
+#include <iostream>
+int main()
+{
+ std::cout << "Hello BoostWorld!\n";
+ return 0;
+}
diff --git a/src/plugins/autotest/unit_test/simple_boost/src/src.pro b/src/plugins/autotest/unit_test/simple_boost/src/src.pro
new file mode 100644
index 0000000000..0393f7894b
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/src/src.pro
@@ -0,0 +1,4 @@
+TEMPLATE = app
+CONFIG -= qt app_bundle
+CONFIG += console
+SOURCES += main.cpp
diff --git a/src/plugins/autotest/unit_test/simple_boost/src/src.qbs b/src/plugins/autotest/unit_test/simple_boost/src/src.qbs
new file mode 100644
index 0000000000..5b24d9d217
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/src/src.qbs
@@ -0,0 +1,6 @@
+import qbs
+CppApplication {
+ type: "application"
+ name: "HelloBoost application"
+ files: [ "main.cpp" ]
+}
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/deco/deco.pro b/src/plugins/autotest/unit_test/simple_boost/tests/deco/deco.pro
new file mode 100644
index 0000000000..0a69f075c2
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/deco/deco.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+CONFIG -= qt app_bundle
+CONFIG += console
+SOURCES += main.cpp
+HEADERS += enab.h
+
+isEmpty(BOOST_INCLUDE_DIR):BOOST_INCLUDE_DIR=$$(BOOST_INCLUDE_DIR)
+!isEmpty(BOOST_INCLUDE_DIR): INCLUDEPATH *= $$BOOST_INCLUDE_DIR
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/deco/deco.qbs b/src/plugins/autotest/unit_test/simple_boost/tests/deco/deco.qbs
new file mode 100644
index 0000000000..1f53178c05
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/deco/deco.qbs
@@ -0,0 +1,11 @@
+import qbs
+import qbs.File
+CppApplication {
+ name: "Decorators Test"
+ type: "application"
+ Properties {
+ condition: project.boostIncDir && File.exists(project.boostIncDir)
+ cpp.includePaths: [project.boostIncDir];
+ }
+ files: [ "enab.h", "main.cpp" ]
+}
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/deco/enab.h b/src/plugins/autotest/unit_test/simple_boost/tests/deco/enab.h
new file mode 100644
index 0000000000..2090c539eb
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/deco/enab.h
@@ -0,0 +1,23 @@
+#pragma once
+#include <boost/test/included/unit_test.hpp>
+
+namespace utf = boost::unit_test;
+
+BOOST_AUTO_TEST_SUITE(Suite1, * utf::disabled())
+ BOOST_AUTO_TEST_CASE(test1)
+ {
+ BOOST_TEST(1 != 1);
+ }
+ BOOST_AUTO_TEST_CASE(Test2, * utf::enabled())
+ {
+ BOOST_TEST(2 != 2);
+ }
+ BOOST_AUTO_TEST_CASE(TestIo, * utf::enable_if<true>())
+ {
+ BOOST_TEST(3 != 3);
+ }
+ BOOST_AUTO_TEST_CASE(TestDb, * utf::enable_if<false>())
+ {
+ BOOST_TEST(4 != 4);
+ }
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/deco/main.cpp b/src/plugins/autotest/unit_test/simple_boost/tests/deco/main.cpp
new file mode 100644
index 0000000000..aef3d912f3
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/deco/main.cpp
@@ -0,0 +1,21 @@
+#define BOOST_TEST_MODULE Suites and Decorators
+#include <boost/test/included/unit_test.hpp>
+#include "enab.h"
+using boost::unit_test::label;
+
+BOOST_AUTO_TEST_CASE(testWithout1, *label("WO")) { BOOST_TEST (true); }
+BOOST_AUTO_TEST_CASE(testWithout2, *label("WO")) { BOOST_TEST (false); }
+BOOST_AUTO_TEST_SUITE(SuiteOuter)
+ BOOST_AUTO_TEST_SUITE(SuiteInner1)
+ BOOST_AUTO_TEST_CASE(Test1) { BOOST_TEST (true); }
+ BOOST_AUTO_TEST_CASE(Test2) { BOOST_TEST (true); }
+ BOOST_AUTO_TEST_SUITE_END()
+ BOOST_AUTO_TEST_SUITE(SuiteInner2, *boost::unit_test::disabled())
+ BOOST_AUTO_TEST_CASE(Test1, *label("I2")) { BOOST_TEST (false); }
+ BOOST_AUTO_TEST_CASE(Test2, *label("I2")) { BOOST_TEST (false); }
+ BOOST_AUTO_TEST_SUITE_END()
+ BOOST_AUTO_TEST_CASE(Test1, *label("O1")) { BOOST_TEST (true); }
+ BOOST_AUTO_TEST_CASE(Test2) { BOOST_TEST (true); }
+ BOOST_AUTO_TEST_CASE(Test2A) { BOOST_TEST (true); }
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.cpp b/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.cpp
new file mode 100644
index 0000000000..54325e5f25
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.cpp
@@ -0,0 +1,18 @@
+#define BOOST_TEST_MODULE fixture example
+#include <boost/test/included/unit_test.hpp>
+
+struct F {
+ F() : i( 0 ) { BOOST_TEST_MESSAGE( "setup fixture" ); }
+ ~F() { BOOST_TEST_MESSAGE( "teardown fixture" ); }
+ int i;
+};
+
+BOOST_FIXTURE_TEST_CASE( test_case1, F )
+{
+ BOOST_TEST( i++ == 1 );
+}
+
+BOOST_FIXTURE_TEST_CASE( test_case2, F, * boost::unit_test::disabled() )
+{
+ BOOST_CHECK_EQUAL( i, 1 );
+}
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.pro b/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.pro
new file mode 100644
index 0000000000..f070f564b0
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+CONFIG -= qt app_bundle
+CONFIG += console
+SOURCES += fix.cpp
+
+isEmpty(BOOST_INCLUDE_DIR):BOOST_INCLUDE_DIR=$$(BOOST_INCLUDE_DIR)
+!isEmpty(BOOST_INCLUDE_DIR): INCLUDEPATH *= $$BOOST_INCLUDE_DIR
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.qbs b/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.qbs
new file mode 100644
index 0000000000..5aa62d7888
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/fix/fix.qbs
@@ -0,0 +1,11 @@
+import qbs
+import qbs.File
+CppApplication {
+ name: "Fixture Test"
+ type: "application"
+ Properties {
+ condition: project.boostIncDir && File.exists(project.boostIncDir)
+ cpp.includePaths: [project.boostIncDir];
+ }
+ files: [ "fix.cpp" ]
+}
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/params/main.cpp b/src/plugins/autotest/unit_test/simple_boost/tests/params/main.cpp
new file mode 100644
index 0000000000..b0821844db
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/params/main.cpp
@@ -0,0 +1,41 @@
+#include <boost/test/included/unit_test.hpp>
+#include <boost/test/parameterized_test.hpp>
+#include <boost/bind.hpp>
+
+using namespace boost::unit_test;
+
+class TestClass
+{
+public:
+ void testMethod()
+ {
+ BOOST_TEST( true );
+ }
+};
+
+void freeTestFunction()
+{
+ BOOST_TEST( true );
+}
+
+void freeTestFunction2(int i)
+{
+ BOOST_TEST( i < 4 );
+}
+
+test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
+{
+ boost::shared_ptr<TestClass> tester( new TestClass );
+
+ framework::master_test_suite().
+ add( BOOST_TEST_CASE( boost::bind( &TestClass::testMethod, tester )));
+
+ framework::master_test_suite().
+ add( BOOST_TEST_CASE( &freeTestFunction) );
+
+ int params[] = {1, 2, 3, 4, 5, 6};
+ framework::master_test_suite().
+ add( BOOST_PARAM_TEST_CASE( &freeTestFunction2, params, params + 6) );
+
+ return nullptr;
+}
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/params/params.pro b/src/plugins/autotest/unit_test/simple_boost/tests/params/params.pro
new file mode 100644
index 0000000000..efea50f870
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/params/params.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+CONFIG -= qt app_bundle
+CONFIG += console
+SOURCES += main.cpp
+
+isEmpty(BOOST_INCLUDE_DIR):BOOST_INCLUDE_DIR=$$(BOOST_INCLUDE_DIR)
+!isEmpty(BOOST_INCLUDE_DIR): INCLUDEPATH *= $$BOOST_INCLUDE_DIR
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/params/params.qbs b/src/plugins/autotest/unit_test/simple_boost/tests/params/params.qbs
new file mode 100644
index 0000000000..5e4633cdb1
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/params/params.qbs
@@ -0,0 +1,11 @@
+import qbs
+import qbs.File
+CppApplication {
+ name: "Using Test Functions"
+ type: "application"
+ Properties {
+ condition: project.boostIncDir && File.exists(project.boostIncDir)
+ cpp.includePaths: [project.boostIncDir];
+ }
+ files: [ "main.cpp" ]
+}
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/tests.pro b/src/plugins/autotest/unit_test/simple_boost/tests/tests.pro
new file mode 100644
index 0000000000..160045bd75
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/tests.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += fix params deco
diff --git a/src/plugins/autotest/unit_test/simple_boost/tests/tests.qbs b/src/plugins/autotest/unit_test/simple_boost/tests/tests.qbs
new file mode 100644
index 0000000000..2033b5de2e
--- /dev/null
+++ b/src/plugins/autotest/unit_test/simple_boost/tests/tests.qbs
@@ -0,0 +1,11 @@
+import qbs
+import qbs.Environment
+Project {
+ name: "Tests"
+ property string boostIncDir: {
+ if (typeof Environment.getEnv("BOOST_INCLUDE_DIR") !== 'undefined')
+ return Environment.getEnv("BOOST_INCLUDE_DIR");
+ return undefined;
+ }
+ references: [ "deco/deco.qbs", "fix/fix.qbs", "params/params.qbs" ]
+}
diff --git a/src/plugins/autotest/unit_test/simple_gt/tests/common/functions.js b/src/plugins/autotest/unit_test/simple_gt/tests/common/functions.js
index 8ce7f31ad9..89cd648a31 100644
--- a/src/plugins/autotest/unit_test/simple_gt/tests/common/functions.js
+++ b/src/plugins/autotest/unit_test/simple_gt/tests/common/functions.js
@@ -1,8 +1,8 @@
-var FileInfo = loadExtension("qbs.FileInfo")
+var FileInfo = require("qbs.FileInfo")
-function getGTestDir(str) {
+function getGTestDir(Qbs, str) {
if (!str) {
- if (qbs.hostOS.contains("linux"))
+ if (Qbs.hostOS.contains("linux"))
return "/usr/include/gtest";
} else {
return FileInfo.joinPaths(str, "googletest");
@@ -10,9 +10,9 @@ function getGTestDir(str) {
return "";
}
-function getGMockDir(str) {
+function getGMockDir(Qbs, str) {
if (!str) {
- if (qbs.hostOS.contains("linux"))
+ if (Qbs.hostOS.contains("linux"))
return "/usr/include/gmock";
} else {
return FileInfo.joinPaths(str, "googlemock");
@@ -20,29 +20,29 @@ function getGMockDir(str) {
return "";
}
-function getGTestAll(str) {
- var gtest = getGTestDir(str);
+function getGTestAll(Qbs, str) {
+ var gtest = getGTestDir(Qbs, str);
if (!gtest)
return [];
return [FileInfo.joinPaths(gtest, "src/gtest-all.cc")];
}
-function getGMockAll(str) {
- var gmock = getGMockDir(str);
+function getGMockAll(Qbs, str) {
+ var gmock = getGMockDir(Qbs, str);
if (!gmock)
return [];
return [FileInfo.joinPaths(gmock, "src/gmock-all.cc")];
}
-function getGTestIncludes(str) {
- var gtest = getGTestDir(str);
+function getGTestIncludes(Qbs, str) {
+ var gtest = getGTestDir(Qbs, str);
if (!gtest)
return [];
return [gtest, FileInfo.joinPaths(gtest, "include")];
}
-function getGMockIncludes(str) {
- var mock = getGMockDir(str);
+function getGMockIncludes(Qbs, str) {
+ var mock = getGMockDir(Qbs, str);
if (!mock)
return [];
return [mock, FileInfo.joinPaths(mock, "include")];
diff --git a/src/plugins/autotest/unit_test/simple_gt/tests/gt1/gt1.qbs b/src/plugins/autotest/unit_test/simple_gt/tests/gt1/gt1.qbs
index f560bb41e6..ac59d83da8 100644
--- a/src/plugins/autotest/unit_test/simple_gt/tests/gt1/gt1.qbs
+++ b/src/plugins/autotest/unit_test/simple_gt/tests/gt1/gt1.qbs
@@ -7,8 +7,8 @@ CppApplication {
type: "application"
name: "googletest1"
- property string gtestDir: googleCommon.getGTestDir(project.googletestDir)
- property string gmockDir: googleCommon.getGMockDir(project.googletestDir)
+ property string gtestDir: googleCommon.getGTestDir(qbs, project.googletestDir)
+ property string gmockDir: googleCommon.getGMockDir(qbs, project.googletestDir)
condition: {
if (File.exists(gtestDir) && File.exists(gmockDir))
@@ -19,8 +19,8 @@ CppApplication {
return false;
}
- cpp.includePaths: [].concat(googleCommon.getGTestIncludes(project.googletestDir))
- .concat(googleCommon.getGMockIncludes(project.googletestDir))
+ cpp.includePaths: [].concat(googleCommon.getGTestIncludes(qbs, project.googletestDir))
+ .concat(googleCommon.getGMockIncludes(qbs, project.googletestDir))
cpp.cxxLanguageVersion: "c++11"
cpp.defines: ["GTEST_LANG_CXX11"]
@@ -30,6 +30,6 @@ CppApplication {
// own stuff
"further.cpp",
"main.cpp",
- ].concat(googleCommon.getGTestAll(project.googletestDir))
- .concat(googleCommon.getGMockAll(project.googletestDir))
+ ].concat(googleCommon.getGTestAll(qbs, project.googletestDir))
+ .concat(googleCommon.getGMockAll(qbs, project.googletestDir))
}
diff --git a/src/plugins/autotest/unit_test/simple_gt/tests/gt2/gt2.qbs b/src/plugins/autotest/unit_test/simple_gt/tests/gt2/gt2.qbs
index b0a898103f..98fdc1e4c9 100644
--- a/src/plugins/autotest/unit_test/simple_gt/tests/gt2/gt2.qbs
+++ b/src/plugins/autotest/unit_test/simple_gt/tests/gt2/gt2.qbs
@@ -7,8 +7,8 @@ CppApplication {
type: "application"
name: "googletest2"
- property string gtestDir: googleCommon.getGTestDir(project.googletestDir)
- property string gmockDir: googleCommon.getGMockDir(project.googletestDir)
+ property string gtestDir: googleCommon.getGTestDir(qbs, project.googletestDir)
+ property string gmockDir: googleCommon.getGMockDir(qbs, project.googletestDir)
Depends { name: "Qt.core" }
@@ -21,8 +21,8 @@ CppApplication {
return false;
}
- cpp.includePaths: [].concat(googleCommon.getGTestIncludes(project.googletestDir))
- .concat(googleCommon.getGMockIncludes(project.googletestDir))
+ cpp.includePaths: [].concat(googleCommon.getGTestIncludes(qbs, project.googletestDir))
+ .concat(googleCommon.getGMockIncludes(qbs, project.googletestDir))
cpp.cxxLanguageVersion: "c++11"
cpp.defines: ["GTEST_LANG_CXX11"]
@@ -31,6 +31,6 @@ CppApplication {
// own stuff
"queuetest.h",
"main.cpp",
- ].concat(googleCommon.getGTestAll(project.googletestDir))
- .concat(googleCommon.getGMockAll(project.googletestDir))
+ ].concat(googleCommon.getGTestAll(qbs, project.googletestDir))
+ .concat(googleCommon.getGMockAll(qbs, project.googletestDir))
}
diff --git a/src/plugins/autotest/unit_test/simple_gt/tests/gt2/queuetest.h b/src/plugins/autotest/unit_test/simple_gt/tests/gt2/queuetest.h
index 7fb47e8e62..815db2bab2 100644
--- a/src/plugins/autotest/unit_test/simple_gt/tests/gt2/queuetest.h
+++ b/src/plugins/autotest/unit_test/simple_gt/tests/gt2/queuetest.h
@@ -25,6 +25,7 @@
#pragma once
+#include <gtest/gtest.h>
#include <QQueue>
class QueueTest : public ::testing::Test
diff --git a/src/plugins/autotest/unit_test/simple_gt/tests/gt3/gt3.qbs b/src/plugins/autotest/unit_test/simple_gt/tests/gt3/gt3.qbs
index 2bd250a588..e41b820594 100644
--- a/src/plugins/autotest/unit_test/simple_gt/tests/gt3/gt3.qbs
+++ b/src/plugins/autotest/unit_test/simple_gt/tests/gt3/gt3.qbs
@@ -7,8 +7,8 @@ CppApplication {
type: "application"
name: "googletest3"
- property string gtestDir: googleCommon.getGTestDir(project.googletestDir)
- property string gmockDir: googleCommon.getGMockDir(project.googletestDir)
+ property string gtestDir: googleCommon.getGTestDir(qbs, project.googletestDir)
+ property string gmockDir: googleCommon.getGMockDir(qbs, project.googletestDir)
Depends { name: "Qt.core" }
@@ -21,8 +21,8 @@ CppApplication {
return false;
}
- cpp.includePaths: [].concat(googleCommon.getGTestIncludes(project.googletestDir))
- .concat(googleCommon.getGMockIncludes(project.googletestDir))
+ cpp.includePaths: [].concat(googleCommon.getGTestIncludes(qbs, project.googletestDir))
+ .concat(googleCommon.getGMockIncludes(qbs, project.googletestDir))
cpp.cxxLanguageVersion: "c++11"
cpp.defines: ["GTEST_LANG_CXX11"]
@@ -31,6 +31,6 @@ CppApplication {
// own stuff
"dummytest.h",
"main.cpp",
- ].concat(googleCommon.getGTestAll(project.googletestDir))
- .concat(googleCommon.getGMockAll(project.googletestDir))
+ ].concat(googleCommon.getGTestAll(qbs, project.googletestDir))
+ .concat(googleCommon.getGMockAll(qbs, project.googletestDir))
}
diff --git a/src/plugins/autotest/unit_test/simple_gt/tests/gt3/main.cpp b/src/plugins/autotest/unit_test/simple_gt/tests/gt3/main.cpp
index 4f048fa177..a7d8591512 100644
--- a/src/plugins/autotest/unit_test/simple_gt/tests/gt3/main.cpp
+++ b/src/plugins/autotest/unit_test/simple_gt/tests/gt3/main.cpp
@@ -56,8 +56,8 @@ static QMap<const char *, QStringList> testValuesSec = {
},
};
-INSTANTIATE_TEST_CASE_P(First, DummyTest, ::testing::ValuesIn(testValues.keys()));
-INSTANTIATE_TEST_CASE_P(Second, DummyTest, ::testing::ValuesIn(testValuesSec.keys()));
+INSTANTIATE_TEST_SUITE_P(First, DummyTest, ::testing::ValuesIn(testValues.keys()));
+INSTANTIATE_TEST_SUITE_P(Second, DummyTest, ::testing::ValuesIn(testValuesSec.keys()));
TEST_P(DummyTest, Easy)
{