File indexing completed on 2024-04-21 04:34:49
0001 /* 0002 SPDX-FileCopyrightText: 2012 Miha Čančula <miha@noughmad.eu> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "phpunitrunjob.h" 0008 #include "phpunittestsuite.h" 0009 #include "testdoxdelegate.h" 0010 #include "testproviderdebug.h" 0011 0012 #include <QStandardPaths> 0013 0014 #include <util/processlinemaker.h> 0015 #include <util/executecompositejob.h> 0016 #include <outputview/outputmodel.h> 0017 #include <interfaces/itestcontroller.h> 0018 #include <interfaces/iruncontroller.h> 0019 #include <interfaces/icore.h> 0020 #include <interfaces/ilauncher.h> 0021 #include <interfaces/ilaunchconfiguration.h> 0022 #include <interfaces/launchconfigurationtype.h> 0023 #include <interfaces/ilaunchmode.h> 0024 0025 #include <KProcess> 0026 #include <KLocalizedString> 0027 #include <KConfigGroup> 0028 0029 PhpUnitRunJob::PhpUnitRunJob(PhpUnitTestSuite* suite, const QStringList& cases, KDevelop::OutputJob::OutputJobVerbosity verbosity, QObject* parent) 0030 : KJob(parent) 0031 , m_process(nullptr) 0032 , m_suite(suite) 0033 , m_cases(cases) 0034 , m_job(nullptr) 0035 , m_outputJob(nullptr) 0036 , m_verbosity(verbosity) 0037 { 0038 } 0039 0040 KJob* createTestJob(QString launchModeId, QStringList arguments ) 0041 { 0042 KDevelop::LaunchConfigurationType* type = KDevelop::ICore::self()->runController()->launchConfigurationTypeForId( QStringLiteral("Script Application") ); 0043 KDevelop::ILaunchMode* mode = KDevelop::ICore::self()->runController()->launchModeForId( launchModeId ); 0044 0045 qCDebug(TESTPROVIDER) << "got mode and type:" << type << type->id() << mode << mode->id(); 0046 Q_ASSERT(type && mode); 0047 0048 KDevelop::ILauncher* launcher = nullptr; 0049 foreach (KDevelop::ILauncher *l, type->launchers()) 0050 { 0051 //qCDebug(TESTPROVIDER) << "available launcher" << l << l->id() << l->supportedModes(); 0052 if (l->supportedModes().contains(mode->id())) { 0053 launcher = l; 0054 break; 0055 } 0056 } 0057 Q_ASSERT(launcher); 0058 0059 KDevelop::ILaunchConfiguration* ilaunch = nullptr; 0060 QList<KDevelop::ILaunchConfiguration*> launchConfigurations = KDevelop::ICore::self()->runController()->launchConfigurations(); 0061 foreach (KDevelop::ILaunchConfiguration *l, launchConfigurations) { 0062 if (l->type() == type && l->config().readEntry("ConfiguredByPhpUnit", false)) { 0063 ilaunch = l; 0064 break; 0065 } 0066 } 0067 if (!ilaunch) { 0068 ilaunch = KDevelop::ICore::self()->runController()->createLaunchConfiguration( type, 0069 qMakePair( mode->id(), launcher->id() ), 0070 nullptr, //TODO add project 0071 i18n("PHPUnit") ); 0072 ilaunch->config().writeEntry("ConfiguredByPhpUnit", true); 0073 //qCDebug(TESTPROVIDER) << "created config, launching"; 0074 } else { 0075 //qCDebug(TESTPROVIDER) << "reusing generated config, launching"; 0076 } 0077 type->configureLaunchFromCmdLineArguments( ilaunch->config(), arguments ); 0078 return KDevelop::ICore::self()->runController()->execute(launchModeId, ilaunch); 0079 } 0080 0081 void PhpUnitRunJob::start() 0082 { 0083 m_process = new KProcess(this); 0084 // TODO: Arguments from test cases 0085 0086 QStringList args; 0087 0088 if (m_cases != m_suite->cases()) 0089 { 0090 args << QStringLiteral("--filter"); 0091 args << '"' + m_cases.join(QStringLiteral("|")) + '"'; 0092 } 0093 0094 args << QStringLiteral("--testdox") << m_suite->name() << m_suite->url().toLocalFile(); 0095 0096 const QString exe = QStandardPaths::findExecutable(QStringLiteral("phpunit")); 0097 if (exe.isEmpty()) { 0098 KDevelop::ITestController* tc = KDevelop::ICore::self()->testController(); 0099 tc->notifyTestRunFinished(m_suite, m_result); 0100 emitResult(); 0101 return; 0102 } 0103 0104 args.prepend(exe); 0105 args.prepend(QStringLiteral("php")); 0106 0107 m_job = createTestJob(QStringLiteral("execute"), args); 0108 0109 m_outputJob = qobject_cast<KDevelop::OutputJob*>(m_job); 0110 if (!m_outputJob) { 0111 if (UnprotectedExecuteCompositeJob* cjob = qobject_cast<UnprotectedExecuteCompositeJob*>(m_job)) { 0112 m_outputJob = qobject_cast<KDevelop::OutputJob*>(cjob->subjobs().last()); 0113 } 0114 } 0115 Q_ASSERT(m_outputJob); 0116 if (m_outputJob) { 0117 m_outputJob->setVerbosity(m_verbosity); 0118 connect(m_outputJob->model(), &QAbstractItemModel::rowsInserted, this, &PhpUnitRunJob::rowsInserted); 0119 } 0120 0121 connect(m_job, &KJob::finished, this, &PhpUnitRunJob::processFinished); 0122 } 0123 0124 bool PhpUnitRunJob::doKill() 0125 { 0126 if (m_job) 0127 { 0128 m_job->kill(); 0129 } 0130 return true; 0131 } 0132 0133 void PhpUnitRunJob::processFinished(KJob* job) 0134 { 0135 if (job->error() == 1) { 0136 m_result.suiteResult = KDevelop::TestResult::Failed; 0137 } else if (job->error() == 0) { 0138 m_result.suiteResult = KDevelop::TestResult::Passed; 0139 foreach (KDevelop::TestResult::TestCaseResult result, m_result.testCaseResults) 0140 { 0141 if (result == KDevelop::TestResult::Failed) 0142 { 0143 m_result.suiteResult = KDevelop::TestResult::Failed; 0144 break; 0145 } 0146 } 0147 } else { 0148 m_result.suiteResult = KDevelop::TestResult::Error; 0149 } 0150 0151 qCDebug(TESTPROVIDER) << m_result.suiteResult << m_result.testCaseResults; 0152 KDevelop::ICore::self()->testController()->notifyTestRunFinished(m_suite, m_result); 0153 emitResult(); 0154 } 0155 0156 void PhpUnitRunJob::rowsInserted(const QModelIndex &parent, int startRow, int endRow) 0157 { 0158 Q_ASSERT(m_outputJob); 0159 static QRegExp testResultLineExp = QRegExp("\\[([x\\s])\\]"); 0160 for (int row = startRow; row <= endRow; ++row) 0161 { 0162 QString line = m_outputJob->model()->data(m_outputJob->model()->index(row, 0, parent), Qt::DisplayRole).toString(); 0163 0164 int i = testResultLineExp.indexIn(line); 0165 if (i > -1) 0166 { 0167 bool passed = testResultLineExp.cap(1) == QLatin1String("x"); 0168 QString testCase = "test" + line.mid(i+4).toLower().remove(' '); 0169 qCDebug(TESTPROVIDER) << "Got result in " << line << " for " << testCase; 0170 if (m_cases.contains(testCase, Qt::CaseInsensitive)) 0171 { 0172 foreach (const QString& realCaseName, m_cases) 0173 { 0174 if (QString::compare(testCase, realCaseName, Qt::CaseInsensitive) == 0) 0175 { 0176 m_result.testCaseResults[testCase] = (passed ? KDevelop::TestResult::Passed : KDevelop::TestResult::Failed); 0177 break; 0178 } 0179 } 0180 } 0181 } 0182 else 0183 { 0184 qCDebug(TESTPROVIDER) << line << testResultLineExp.pattern() << i; 0185 } 0186 } 0187 } 0188 0189 #include "moc_phpunitrunjob.cpp"