diff --git a/projectmanagers/cmake/testing/ctestrunjob.cpp b/projectmanagers/cmake/testing/ctestrunjob.cpp index 3f5ab5a86f..ffc74bd39f 100644 --- a/projectmanagers/cmake/testing/ctestrunjob.cpp +++ b/projectmanagers/cmake/testing/ctestrunjob.cpp @@ -1,222 +1,222 @@ /* This file is part of KDevelop Copyright 2012 Miha Čančula This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ctestrunjob.h" #include "ctestsuite.h" #include "qttestdelegate.h" #include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; CTestRunJob::CTestRunJob(CTestSuite* suite, const QStringList& cases, OutputJob::OutputJobVerbosity verbosity, QObject* parent) : KJob(parent) , m_suite(suite) , m_cases(cases) , m_job(nullptr) , m_outputJob(nullptr) , m_verbosity(verbosity) { foreach (const QString& testCase, cases) { m_caseResults[testCase] = TestResult::NotRun; } setCapabilities(Killable); } static KJob* createTestJob(const QString& launchModeId, const QStringList& arguments, const QString &workingDirectory) { LaunchConfigurationType* type = ICore::self()->runController()->launchConfigurationTypeForId( QStringLiteral("Native Application") ); ILaunchMode* mode = ICore::self()->runController()->launchModeForId( launchModeId ); qCDebug(CMAKE) << "got mode and type:" << type << type->id() << mode << mode->id(); Q_ASSERT(type && mode); ILauncher* launcher = nullptr; foreach (ILauncher *l, type->launchers()) { //qCDebug(CMAKE) << "available launcher" << l << l->id() << l->supportedModes(); if (l->supportedModes().contains(mode->id())) { launcher = l; break; } } Q_ASSERT(launcher); ILaunchConfiguration* ilaunch = nullptr; QList launchConfigurations = ICore::self()->runController()->launchConfigurations(); foreach (ILaunchConfiguration *l, launchConfigurations) { if (l->type() == type && l->config().readEntry("ConfiguredByCTest", false)) { ilaunch = l; break; } } if (!ilaunch) { ilaunch = ICore::self()->runController()->createLaunchConfiguration( type, qMakePair( mode->id(), launcher->id() ), nullptr, //TODO add project i18n("CTest") ); ilaunch->config().writeEntry("ConfiguredByCTest", true); //qCDebug(CMAKE) << "created config, launching"; } else { //qCDebug(CMAKE) << "reusing generated config, launching"; } if (!workingDirectory.isEmpty()) ilaunch->config().writeEntry( "Working Directory", QUrl::fromLocalFile( workingDirectory ) ); type->configureLaunchFromCmdLineArguments( ilaunch->config(), arguments ); return ICore::self()->runController()->execute(launchModeId, ilaunch); } void CTestRunJob::start() { // if (!m_suite->cases().isEmpty()) // { // TODO: Find a better way of determining whether QTestLib is used by this test // qCDebug(CMAKE) << "Setting a QtTestDelegate"; // setDelegate(new QtTestDelegate); // } // setStandardToolView(IOutputView::RunView); QStringList arguments = m_cases; if (m_cases.isEmpty() && !m_suite->arguments().isEmpty()) { arguments = m_suite->arguments(); } QStringList cases_selected = arguments; arguments.prepend(m_suite->executable().toLocalFile()); const QString workingDirectory = m_suite->properties().value(QLatin1String("WORKING_DIRECTORY"), QString()); m_job = createTestJob(QStringLiteral("execute"), arguments, workingDirectory); if (ExecuteCompositeJob* cjob = qobject_cast(m_job)) { m_outputJob = cjob->findChild(); Q_ASSERT(m_outputJob); m_outputJob->setVerbosity(m_verbosity); - QString testName = arguments.value(0).split('/').last(); + QString testName = m_suite->name(); QString title; if (cases_selected.count() == 1) title = i18nc("running test %1, %2 test case", "CTest %1: %2", testName, cases_selected.value(0)); else title = i18ncp("running test %1, %2 number of test cases", "CTest %2 (%1)", "CTest %2 (%1)", cases_selected.count(), testName); m_outputJob->setTitle(title); connect(m_outputJob->model(), &QAbstractItemModel::rowsInserted, this, &CTestRunJob::rowsInserted); } connect(m_job, &KJob::finished, this, &CTestRunJob::processFinished); ICore::self()->testController()->notifyTestRunStarted(m_suite, cases_selected); } bool CTestRunJob::doKill() { if (m_job) { m_job->kill(); } return true; } void CTestRunJob::processFinished(KJob* job) { TestResult result; result.testCaseResults = m_caseResults; if (job->error() == OutputJob::FailedShownError) { result.suiteResult = TestResult::Failed; } else if (job->error() == KJob::NoError) { result.suiteResult = TestResult::Passed; } else { result.suiteResult = TestResult::Error; } // in case the job was killed, mark this job as killed as well if (job->error() == KJob::KilledJobError) { setError(KJob::KilledJobError); setErrorText(QStringLiteral("Child job was killed.")); } qCDebug(CMAKE) << result.suiteResult << result.testCaseResults; ICore::self()->testController()->notifyTestRunFinished(m_suite, result); emitResult(); } void CTestRunJob::rowsInserted(const QModelIndex &parent, int startRow, int endRow) { // This regular expression matches the name of the testcase (whatever between "::" and "(", indeed ) // For example, from: // PASS : ExpTest::testExp(sum) // matches "testExp" static QRegExp caseRx("::(.*)\\(", Qt::CaseSensitive, QRegExp::RegExp2); for (int row = startRow; row <= endRow; ++row) { QString line = m_outputJob->model()->data(m_outputJob->model()->index(row, 0, parent), Qt::DisplayRole).toString(); QString testCase; if (caseRx.indexIn(line) >= 0) { testCase = caseRx.cap(1); } TestResult::TestCaseResult prevResult = m_caseResults.value(testCase, TestResult::NotRun); if (prevResult == TestResult::Passed || prevResult == TestResult::NotRun) { TestResult::TestCaseResult result = TestResult::NotRun; const bool expectFail = m_suite->properties().value(QStringLiteral("WILL_FAIL"), QStringLiteral("FALSE")) == QLatin1String("TRUE"); if (line.startsWith(QLatin1String("PASS :"))) { result = expectFail ? TestResult::UnexpectedPass : TestResult::Passed; } else if (line.startsWith(QLatin1String("FAIL! :"))) { result = expectFail ? TestResult::ExpectedFail : TestResult::Failed; } else if (line.startsWith(QLatin1String("XFAIL :"))) { result = TestResult::ExpectedFail; } else if (line.startsWith(QLatin1String("XPASS :"))) { result = TestResult::UnexpectedPass; } else if (line.startsWith(QLatin1String("SKIP :"))) { result = TestResult::Skipped; } if (result != TestResult::NotRun) { m_caseResults[testCase] = result; } } } }