2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2022-04-01 14:15:30 +02:00
|
|
|
#include "processtestapp/processtestapp.h"
|
|
|
|
|
|
2022-03-04 17:13:10 +01:00
|
|
|
#include <app/app_version.h>
|
|
|
|
|
|
2024-09-12 09:36:23 +02:00
|
|
|
#include <utils/async.h>
|
2021-06-14 15:09:11 +02:00
|
|
|
#include <utils/environment.h>
|
2014-02-05 10:43:21 +01:00
|
|
|
#include <utils/hostosinfo.h>
|
2024-02-27 16:08:45 +01:00
|
|
|
#include <utils/qtcprocess.h>
|
2022-04-01 15:14:05 +02:00
|
|
|
#include <utils/processinfo.h>
|
2022-06-29 18:41:50 +02:00
|
|
|
#include <utils/processinterface.h>
|
2024-11-01 12:46:18 +01:00
|
|
|
#include <utils/processreaper.h>
|
2022-03-04 17:14:13 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2010-10-14 18:05:43 +02:00
|
|
|
#include <utils/stringutils.h>
|
2022-03-04 17:13:10 +01:00
|
|
|
#include <utils/temporarydirectory.h>
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2021-08-30 16:29:08 +02:00
|
|
|
#include <QElapsedTimer>
|
2021-06-14 15:09:11 +02:00
|
|
|
#include <QRegularExpression>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QtTest>
|
2010-10-14 18:05:43 +02:00
|
|
|
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
2024-01-22 17:27:24 +01:00
|
|
|
using namespace std::chrono;
|
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
|
|
2022-03-21 18:02:53 +01:00
|
|
|
// This handler is inspired by the one used in qtbase/tests/auto/corelib/io/qfile/tst_qfile.cpp
|
|
|
|
|
class MessageHandler {
|
|
|
|
|
public:
|
|
|
|
|
MessageHandler(QtMessageHandler messageHandler = handler)
|
|
|
|
|
{
|
|
|
|
|
s_oldMessageHandler = qInstallMessageHandler(messageHandler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~MessageHandler()
|
|
|
|
|
{
|
|
|
|
|
qInstallMessageHandler(s_oldMessageHandler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int destroyCount()
|
|
|
|
|
{
|
|
|
|
|
return s_destroyCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
static void handler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
|
|
|
|
{
|
|
|
|
|
if (msg.contains("QProcess: Destroyed while process")
|
|
|
|
|
&& msg.contains("is still running.")) {
|
|
|
|
|
++s_destroyCount;
|
|
|
|
|
}
|
|
|
|
|
// Defer to old message handler.
|
|
|
|
|
if (s_oldMessageHandler)
|
|
|
|
|
s_oldMessageHandler(type, context, msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QtMessageHandler s_oldMessageHandler;
|
|
|
|
|
static int s_destroyCount;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int MessageHandler::s_destroyCount = 0;
|
|
|
|
|
QtMessageHandler MessageHandler::s_oldMessageHandler = 0;
|
|
|
|
|
|
2022-06-03 11:12:29 +02:00
|
|
|
static constexpr char s_skipTerminateOnWindows[] =
|
|
|
|
|
"Windows implementation of this test is lacking handling of WM_CLOSE message.";
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
class tst_Process : public QObject
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
|
void initTestCase();
|
2014-02-05 10:43:21 +01:00
|
|
|
|
2024-09-12 09:36:23 +02:00
|
|
|
// Keep me as a first test to ensure that all singletons are working OK
|
|
|
|
|
// when being instantiated from the non-main thread.
|
|
|
|
|
void processReaperCreatedInNonMainThread();
|
2023-03-20 11:30:07 +01:00
|
|
|
void testEnv()
|
|
|
|
|
{
|
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
|
QSKIP("Skipping env test on Windows");
|
|
|
|
|
|
|
|
|
|
QProcess qproc;
|
|
|
|
|
FilePath envPath = Environment::systemEnvironment().searchInPath("env");
|
|
|
|
|
|
|
|
|
|
qproc.setProgram(envPath.nativePath());
|
|
|
|
|
qproc.start();
|
|
|
|
|
qproc.waitForFinished();
|
|
|
|
|
QByteArray qoutput = qproc.readAllStandardOutput() + qproc.readAllStandardError();
|
|
|
|
|
qDebug() << "QProcess output:" << qoutput;
|
|
|
|
|
QCOMPARE(qproc.exitCode(), 0);
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
Process proc;
|
2024-05-16 12:31:24 +02:00
|
|
|
proc.setCommand(CommandLine{envPath});
|
2023-05-04 17:20:29 +02:00
|
|
|
proc.runBlocking();
|
|
|
|
|
QCOMPARE(proc.exitCode(), 0);
|
2024-01-21 17:17:46 +01:00
|
|
|
const QByteArray output = proc.rawStdOut() + proc.rawStdErr();
|
2023-05-04 17:20:29 +02:00
|
|
|
qDebug() << "Process output:" << output;
|
2023-03-20 11:30:07 +01:00
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
QCOMPARE(output.size() > 0, qoutput.size() > 0);
|
2023-03-20 11:30:07 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-06 16:19:54 +01:00
|
|
|
void multiRead_data();
|
2022-08-10 14:38:06 +02:00
|
|
|
void multiRead();
|
2010-10-14 18:05:43 +02:00
|
|
|
void splitArgs_data();
|
|
|
|
|
void splitArgs();
|
|
|
|
|
void prepareArgs_data();
|
|
|
|
|
void prepareArgs();
|
|
|
|
|
void prepareArgsEnv_data();
|
|
|
|
|
void prepareArgsEnv();
|
|
|
|
|
void iterations_data();
|
|
|
|
|
void iterations();
|
2014-02-05 10:43:21 +01:00
|
|
|
void iteratorEditsWindows();
|
|
|
|
|
void iteratorEditsLinux();
|
2021-05-26 18:45:49 +02:00
|
|
|
void exitCode_data();
|
|
|
|
|
void exitCode();
|
2021-05-26 03:56:03 +02:00
|
|
|
void runBlockingStdOut_data();
|
|
|
|
|
void runBlockingStdOut();
|
2022-10-07 12:05:37 +02:00
|
|
|
void runBlockingSignal_data();
|
|
|
|
|
void runBlockingSignal();
|
2021-06-09 01:00:19 +02:00
|
|
|
void lineCallback();
|
2022-10-07 12:05:37 +02:00
|
|
|
void lineSignal();
|
2022-04-25 07:18:00 +02:00
|
|
|
void waitForStartedAfterStarted();
|
|
|
|
|
void waitForStartedAfterStarted2();
|
2021-08-25 09:32:00 +02:00
|
|
|
void waitForStartedAndFinished();
|
2022-06-29 18:41:50 +02:00
|
|
|
void notRunningAfterStartingNonExistingProgram_data();
|
2021-08-30 16:29:08 +02:00
|
|
|
void notRunningAfterStartingNonExistingProgram();
|
2022-03-30 11:14:48 +02:00
|
|
|
void channelForwarding_data();
|
|
|
|
|
void channelForwarding();
|
|
|
|
|
void mergedChannels_data();
|
|
|
|
|
void mergedChannels();
|
2022-06-03 11:12:29 +02:00
|
|
|
void destroyBlockingProcess_data();
|
|
|
|
|
void destroyBlockingProcess();
|
2023-12-06 13:10:05 +01:00
|
|
|
void flushFinishedWhileWaitingForReadyRead_data();
|
2021-11-04 10:27:08 +01:00
|
|
|
void flushFinishedWhileWaitingForReadyRead();
|
2022-06-22 15:17:25 +02:00
|
|
|
void crash();
|
2022-03-21 16:24:22 +01:00
|
|
|
void crashAfterOneSecond();
|
2022-04-01 15:02:23 +02:00
|
|
|
void recursiveCrashingProcess();
|
2022-04-01 15:14:05 +02:00
|
|
|
void recursiveBlockingProcess();
|
2022-06-03 11:12:29 +02:00
|
|
|
void quitBlockingProcess_data();
|
|
|
|
|
void quitBlockingProcess();
|
2023-01-23 13:14:35 +01:00
|
|
|
void tarPipe();
|
2023-04-14 10:00:08 +02:00
|
|
|
void stdinToShell();
|
2024-01-10 23:01:48 +01:00
|
|
|
void eventLoopMode_data();
|
|
|
|
|
void eventLoopMode();
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2021-08-13 13:30:43 +02:00
|
|
|
void cleanupTestCase();
|
|
|
|
|
|
2010-10-14 18:05:43 +02:00
|
|
|
private:
|
2014-02-05 10:43:21 +01:00
|
|
|
void iteratorEditsHelper(OsType osType);
|
|
|
|
|
|
|
|
|
|
Environment envWindows;
|
|
|
|
|
Environment envLinux;
|
|
|
|
|
|
2011-03-28 14:50:32 +02:00
|
|
|
QString homeStr;
|
|
|
|
|
QString home;
|
2022-03-21 18:02:53 +01:00
|
|
|
|
|
|
|
|
MessageHandler *msgHandler = nullptr;
|
2010-10-14 18:05:43 +02:00
|
|
|
};
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::initTestCase()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
2022-03-21 18:02:53 +01:00
|
|
|
msgHandler = new MessageHandler;
|
2023-12-06 16:19:54 +01:00
|
|
|
TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/"
|
2022-03-04 17:13:10 +01:00
|
|
|
+ Core::Constants::IDE_CASED_ID + "-XXXXXX");
|
2022-04-01 14:15:30 +02:00
|
|
|
SubProcessConfig::setPathToProcessTestApp(QLatin1String(PROCESS_TESTAPP));
|
2021-05-26 18:45:49 +02:00
|
|
|
|
2011-03-28 14:50:32 +02:00
|
|
|
homeStr = QLatin1String("@HOME@");
|
|
|
|
|
home = QDir::homePath();
|
2014-02-05 10:43:21 +01:00
|
|
|
|
|
|
|
|
QStringList env;
|
|
|
|
|
env << "empty=" << "word=hi" << "words=hi ho" << "spacedwords= hi ho sucker ";
|
|
|
|
|
envWindows = Environment(env, OsTypeWindows);
|
|
|
|
|
envLinux = Environment(env, OsTypeLinux);
|
2010-10-14 18:05:43 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::cleanupTestCase()
|
2021-08-13 13:30:43 +02:00
|
|
|
{
|
2024-11-01 12:46:18 +01:00
|
|
|
ProcessReaper::deleteAll();
|
2022-03-21 18:02:53 +01:00
|
|
|
const int destroyCount = msgHandler->destroyCount();
|
|
|
|
|
delete msgHandler;
|
|
|
|
|
if (destroyCount)
|
|
|
|
|
qDebug() << "Received" << destroyCount << "messages about destroying running QProcess!";
|
|
|
|
|
QCOMPARE(destroyCount, 0);
|
2021-08-13 13:30:43 +02:00
|
|
|
}
|
2014-02-05 10:43:21 +01:00
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
Q_DECLARE_METATYPE(ProcessArgs::SplitError)
|
2023-12-06 16:19:54 +01:00
|
|
|
Q_DECLARE_METATYPE(OsType)
|
|
|
|
|
Q_DECLARE_METATYPE(ProcessResult)
|
|
|
|
|
|
2024-09-12 09:36:23 +02:00
|
|
|
static bool deleteRunningProcess()
|
|
|
|
|
{
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {});
|
|
|
|
|
Process process;
|
|
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
process.start();
|
|
|
|
|
process.waitForStarted();
|
|
|
|
|
return process.isRunning();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tst_Process::processReaperCreatedInNonMainThread()
|
|
|
|
|
{
|
2024-11-01 12:46:18 +01:00
|
|
|
ProcessReaper::deleteAll();
|
2024-09-12 09:36:23 +02:00
|
|
|
|
|
|
|
|
auto future = Utils::asyncRun(deleteRunningProcess);
|
|
|
|
|
future.waitForFinished();
|
|
|
|
|
QVERIFY(future.result());
|
|
|
|
|
|
2024-11-01 12:46:18 +01:00
|
|
|
ProcessReaper::deleteAll();
|
2024-09-12 09:36:23 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-06 16:19:54 +01:00
|
|
|
void tst_Process::multiRead_data()
|
|
|
|
|
{
|
|
|
|
|
QTest::addColumn<QProcess::ProcessChannel>("processChannel");
|
|
|
|
|
|
|
|
|
|
QTest::newRow("StandardOutput") << QProcess::StandardOutput;
|
|
|
|
|
QTest::newRow("StandardError") << QProcess::StandardError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QByteArray readData(Process *process, QProcess::ProcessChannel processChannel)
|
|
|
|
|
{
|
2024-01-05 13:19:34 +01:00
|
|
|
return processChannel == QProcess::StandardOutput ? process->readAllRawStandardOutput()
|
|
|
|
|
: process->readAllRawStandardError();
|
2023-12-06 16:19:54 +01:00
|
|
|
}
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::multiRead()
|
2022-08-10 14:38:06 +02:00
|
|
|
{
|
2023-12-06 16:19:54 +01:00
|
|
|
QFETCH(QProcess::ProcessChannel, processChannel);
|
|
|
|
|
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::ChannelEchoer::envVar(),
|
|
|
|
|
QString::number(int(processChannel)));
|
2022-09-06 15:47:30 +02:00
|
|
|
|
2022-08-10 14:38:06 +02:00
|
|
|
QByteArray buffer;
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2023-12-06 14:47:56 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
2022-08-10 14:38:06 +02:00
|
|
|
|
2023-12-06 16:19:54 +01:00
|
|
|
process.setProcessMode(ProcessMode::Writer);
|
2022-08-10 14:38:06 +02:00
|
|
|
process.start();
|
|
|
|
|
|
2023-12-06 14:47:56 +01:00
|
|
|
QVERIFY(process.waitForStarted());
|
2022-08-10 14:38:06 +02:00
|
|
|
|
2023-12-06 14:47:56 +01:00
|
|
|
process.writeRaw("hi\n");
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(process.waitForReadyRead(1s));
|
2023-12-06 16:19:54 +01:00
|
|
|
buffer = readData(&process, processChannel);
|
2024-01-04 20:13:14 +01:00
|
|
|
QCOMPARE(buffer, QByteArray("hi"));
|
2022-08-10 14:38:06 +02:00
|
|
|
|
2023-12-06 14:47:56 +01:00
|
|
|
process.writeRaw("you\n");
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(process.waitForReadyRead(1s));
|
2023-12-06 16:19:54 +01:00
|
|
|
buffer = readData(&process, processChannel);
|
2024-01-04 20:13:14 +01:00
|
|
|
QCOMPARE(buffer, QByteArray("you"));
|
2023-12-06 14:47:56 +01:00
|
|
|
|
|
|
|
|
process.writeRaw("exit\n");
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(process.waitForFinished(1s));
|
2022-08-10 14:38:06 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::splitArgs_data()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<QString>("in");
|
|
|
|
|
QTest::addColumn<QString>("out");
|
2021-05-06 13:07:36 +02:00
|
|
|
QTest::addColumn<ProcessArgs::SplitError>("err");
|
2023-12-06 16:19:54 +01:00
|
|
|
QTest::addColumn<OsType>("os");
|
2010-10-14 18:05:43 +02:00
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char * const in;
|
|
|
|
|
const char * const out;
|
2021-05-06 13:07:36 +02:00
|
|
|
const ProcessArgs::SplitError err;
|
2014-02-05 10:43:21 +01:00
|
|
|
const OsType os;
|
2010-10-14 18:05:43 +02:00
|
|
|
} vals[] = {
|
2021-05-06 13:07:36 +02:00
|
|
|
{"", "", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{" ", "", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi", "hi", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{" hi ho ", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\"hi ho\" \"hi\" ho ", "\"hi ho\" hi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\", "\\", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\\"", "\"\"\\^\"\"\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\"hi\"\"\"ho\"", "\"hi\"\\^\"\"ho\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\\\\\\"", "\"\"\\\\\\^\"\"\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{" ^^ ", "\"^^\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi\"", "", ProcessArgs::BadQuoting, OsTypeWindows},
|
|
|
|
|
{"hi\"dood", "", ProcessArgs::BadQuoting, OsTypeWindows},
|
|
|
|
|
{"%var%", "%var%", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
|
|
|
|
|
{"", "", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" ", "", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi", "hi", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" hi ho ", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"'hi ho' \"hi\" ho ", "'hi ho' hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" \\ ", "' '", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" \\\" ", "'\"'", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" '\"' ", "'\"'", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" \"\\\"\" ", "'\"'", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi'", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"hi\"dood", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"$var", "'$var'", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"~", "@HOME@", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"~ foo", "@HOME@ foo", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"foo ~", "foo @HOME@", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"~/foo", "@HOME@/foo", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"~foo", "'~foo'", ProcessArgs::SplitOk, OsTypeLinux}
|
2010-10-14 18:05:43 +02:00
|
|
|
};
|
|
|
|
|
|
2014-02-05 10:43:21 +01:00
|
|
|
for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
|
|
|
|
|
QString out = QString::fromLatin1(vals[i].out);
|
|
|
|
|
if (vals[i].os == OsTypeLinux)
|
|
|
|
|
out.replace(homeStr, home);
|
2010-10-14 18:05:43 +02:00
|
|
|
QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
|
2014-02-05 10:43:21 +01:00
|
|
|
<< out << vals[i].err << vals[i].os;
|
|
|
|
|
}
|
2010-10-14 18:05:43 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::splitArgs()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(QString, in);
|
|
|
|
|
QFETCH(QString, out);
|
2021-05-06 13:07:36 +02:00
|
|
|
QFETCH(ProcessArgs::SplitError, err);
|
2023-12-06 16:19:54 +01:00
|
|
|
QFETCH(OsType, os);
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::SplitError outerr;
|
|
|
|
|
QString outstr = ProcessArgs::joinArgs(ProcessArgs::splitArgs(in, os, false, &outerr), os);
|
2010-10-14 18:05:43 +02:00
|
|
|
QCOMPARE(outerr, err);
|
2021-05-06 13:07:36 +02:00
|
|
|
if (err == ProcessArgs::SplitOk)
|
2010-10-14 18:05:43 +02:00
|
|
|
QCOMPARE(outstr, out);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::prepareArgs_data()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<QString>("in");
|
|
|
|
|
QTest::addColumn<QString>("out");
|
2021-05-06 13:07:36 +02:00
|
|
|
QTest::addColumn<ProcessArgs::SplitError>("err");
|
2014-02-05 10:43:21 +01:00
|
|
|
QTest::addColumn<OsType>("os");
|
2010-10-14 18:05:43 +02:00
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char * const in;
|
|
|
|
|
const char * const out;
|
2021-05-06 13:07:36 +02:00
|
|
|
const ProcessArgs::SplitError err;
|
2014-02-05 10:43:21 +01:00
|
|
|
const OsType os;
|
2010-10-14 18:05:43 +02:00
|
|
|
} vals[] = {
|
2021-05-06 13:07:36 +02:00
|
|
|
{" ", " ", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"", "", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi", "hi", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{" hi ho ", " hi ho ", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\"hi ho\" \"hi\" ho ", "\"hi ho\" \"hi\" ho ", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\", "\\", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\\"", "\\\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\"hi\"\"ho\"", "\"hi\"\"ho\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\\\\\\"", "\\\\\\\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"^^", "^", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi\"", "hi\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi\"dood", "hi\"dood", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"%var%", "", ProcessArgs::FoundMeta, OsTypeWindows},
|
|
|
|
|
{"echo hi > file", "", ProcessArgs::FoundMeta, OsTypeWindows},
|
|
|
|
|
|
|
|
|
|
{"", "", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" ", "", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi", "hi", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" hi ho ", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"'hi ho' \"hi\" ho ", "'hi ho' hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" \\ ", "' '", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi'", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"hi\"dood", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"$var", "", ProcessArgs::FoundMeta, OsTypeLinux},
|
|
|
|
|
{"~", "@HOME@", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"~ foo", "@HOME@ foo", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"~/foo", "@HOME@/foo", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"~foo", "", ProcessArgs::FoundMeta, OsTypeLinux}
|
2010-10-14 18:05:43 +02:00
|
|
|
};
|
|
|
|
|
|
2014-02-05 10:43:21 +01:00
|
|
|
for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
|
|
|
|
|
QString out = QString::fromLatin1(vals[i].out);
|
|
|
|
|
if (vals[i].os == OsTypeLinux)
|
|
|
|
|
out.replace(homeStr, home);
|
2010-10-14 18:05:43 +02:00
|
|
|
QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
|
2014-02-05 10:43:21 +01:00
|
|
|
<< out << vals[i].err << vals[i].os;
|
|
|
|
|
}
|
2010-10-14 18:05:43 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::prepareArgs()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(QString, in);
|
|
|
|
|
QFETCH(QString, out);
|
2021-05-06 13:07:36 +02:00
|
|
|
QFETCH(ProcessArgs::SplitError, err);
|
2014-02-05 10:43:21 +01:00
|
|
|
QFETCH(OsType, os);
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::SplitError outerr;
|
|
|
|
|
ProcessArgs args = ProcessArgs::prepareArgs(in, &outerr, os);
|
2014-02-05 10:43:21 +01:00
|
|
|
QString outstr = args.toString();
|
|
|
|
|
|
2010-10-14 18:05:43 +02:00
|
|
|
QCOMPARE(outerr, err);
|
2021-05-06 13:07:36 +02:00
|
|
|
if (err == ProcessArgs::SplitOk)
|
2010-10-14 18:05:43 +02:00
|
|
|
QCOMPARE(outstr, out);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::prepareArgsEnv_data()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<QString>("in");
|
|
|
|
|
QTest::addColumn<QString>("out");
|
2021-05-06 13:07:36 +02:00
|
|
|
QTest::addColumn<ProcessArgs::SplitError>("err");
|
2014-02-05 10:43:21 +01:00
|
|
|
QTest::addColumn<OsType>("os");
|
2010-10-14 18:05:43 +02:00
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char * const in;
|
|
|
|
|
const char * const out;
|
2021-05-06 13:07:36 +02:00
|
|
|
const ProcessArgs::SplitError err;
|
2014-02-05 10:43:21 +01:00
|
|
|
const OsType os;
|
2010-10-14 18:05:43 +02:00
|
|
|
} vals[] = {
|
2021-05-06 13:07:36 +02:00
|
|
|
{" ", " ", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"", "", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi", "hi", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{" hi ho ", " hi ho ", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\"hi ho\" \"hi\" ho ", "\"hi ho\" \"hi\" ho ", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\", "\\", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\\"", "\\\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\"hi\"\"ho\"", "\"hi\"\"ho\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"\\\\\\\"", "\\\\\\\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"^^", "^", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi\"", "hi\"", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"hi\"dood", "hi\"dood", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"%empty%", "%empty%", ProcessArgs::SplitOk, OsTypeWindows}, // Yep, no empty variables on Windows.
|
|
|
|
|
{"%word%", "hi", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{" %word% ", " hi ", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"%words%", "hi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"%nonsense%words%", "%nonsensehi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"fail%nonsense%words%", "fail%nonsensehi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"%words%words%", "hi howords%", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"%words%%words%", "hi hohi ho", ProcessArgs::SplitOk, OsTypeWindows},
|
|
|
|
|
{"echo hi > file", "", ProcessArgs::FoundMeta, OsTypeWindows},
|
|
|
|
|
|
|
|
|
|
{"", "", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" ", "", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi", "hi", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi ho", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" hi ho ", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"'hi ho' \"hi\" ho ", "'hi ho' hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" \\ ", "' '", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi'", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"hi\"dood", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"$empty", "", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"$word", "hi", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" $word ", "hi", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"${word}", "hi", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{" ${word} ", "hi", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"$words", "hi ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"$spacedwords", "hi ho sucker", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi${empty}ho", "hiho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi${words}ho", "hihi hoho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"hi${spacedwords}ho", "hi hi ho sucker ho", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"${", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"${var", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"${var ", "", ProcessArgs::FoundMeta, OsTypeLinux},
|
|
|
|
|
{"\"hi${words}ho\"", "'hihi hoho'", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"\"hi${spacedwords}ho\"", "'hi hi ho sucker ho'", ProcessArgs::SplitOk, OsTypeLinux},
|
|
|
|
|
{"\"${", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"\"${var", "", ProcessArgs::BadQuoting, OsTypeLinux},
|
|
|
|
|
{"\"${var ", "", ProcessArgs::FoundMeta, OsTypeLinux},
|
2010-10-14 18:05:43 +02:00
|
|
|
};
|
|
|
|
|
|
2014-02-05 10:43:21 +01:00
|
|
|
for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
|
|
|
|
|
QString out = QString::fromLatin1(vals[i].out);
|
|
|
|
|
if (vals[i].os == OsTypeLinux)
|
|
|
|
|
out.replace(homeStr, home);
|
2010-10-14 18:05:43 +02:00
|
|
|
QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
|
2014-02-05 10:43:21 +01:00
|
|
|
<< out << vals[i].err << vals[i].os;
|
|
|
|
|
}
|
2010-10-14 18:05:43 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::prepareArgsEnv()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(QString, in);
|
|
|
|
|
QFETCH(QString, out);
|
2021-05-06 13:07:36 +02:00
|
|
|
QFETCH(ProcessArgs::SplitError, err);
|
2014-02-05 10:43:21 +01:00
|
|
|
QFETCH(OsType, os);
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::SplitError outerr;
|
|
|
|
|
ProcessArgs args = ProcessArgs::prepareArgs(in, &outerr, os, os == OsTypeLinux ? &envLinux : &envWindows);
|
2014-02-05 10:43:21 +01:00
|
|
|
QString outstr = args.toString();
|
|
|
|
|
|
2010-10-14 18:05:43 +02:00
|
|
|
QCOMPARE(outerr, err);
|
2021-05-06 13:07:36 +02:00
|
|
|
if (err == ProcessArgs::SplitOk)
|
2010-10-14 18:05:43 +02:00
|
|
|
QCOMPARE(outstr, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::iterations_data()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<QString>("in");
|
|
|
|
|
QTest::addColumn<QString>("out");
|
2014-02-05 10:43:21 +01:00
|
|
|
QTest::addColumn<OsType>("os");
|
2010-10-14 18:05:43 +02:00
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char * const in;
|
|
|
|
|
const char * const out;
|
2014-02-05 10:43:21 +01:00
|
|
|
OsType os;
|
2010-10-14 18:05:43 +02:00
|
|
|
} vals[] = {
|
2017-02-22 15:09:35 +01:00
|
|
|
{"", "", OsTypeWindows},
|
|
|
|
|
{"hi", "hi", OsTypeWindows},
|
|
|
|
|
{" hi ", "hi", OsTypeWindows},
|
|
|
|
|
{"hi ho", "hi ho", OsTypeWindows},
|
|
|
|
|
{"\"hi ho\" sucker", "\"hi ho\" sucker", OsTypeWindows},
|
|
|
|
|
{"\"hi\"^\"\"ho\" sucker", "\"hi\"\\^\"\"ho\" sucker", OsTypeWindows},
|
|
|
|
|
{"\"hi\"\\^\"\"ho\" sucker", "\"hi\"\\^\"\"ho\" sucker", OsTypeWindows},
|
|
|
|
|
{"hi^|ho", "\"hi|ho\"", OsTypeWindows},
|
|
|
|
|
{"c:\\", "c:\\", OsTypeWindows},
|
|
|
|
|
{"\"c:\\\\\"", "c:\\", OsTypeWindows},
|
|
|
|
|
{"\\hi\\ho", "\\hi\\ho", OsTypeWindows},
|
|
|
|
|
{"hi null%", "hi null%", OsTypeWindows},
|
|
|
|
|
{"hi null% ho", "hi null% ho", OsTypeWindows},
|
|
|
|
|
{"hi null%here ho", "hi null%here ho", OsTypeWindows},
|
|
|
|
|
{"hi null%here%too ho", "hi {} ho", OsTypeWindows},
|
|
|
|
|
{"echo hello | more", "echo hello", OsTypeWindows},
|
|
|
|
|
{"echo hello| more", "echo hello", OsTypeWindows},
|
|
|
|
|
|
|
|
|
|
{"", "", OsTypeLinux},
|
|
|
|
|
{" ", "", OsTypeLinux},
|
|
|
|
|
{"hi", "hi", OsTypeLinux},
|
|
|
|
|
{" hi ", "hi", OsTypeLinux},
|
|
|
|
|
{"'hi'", "hi", OsTypeLinux},
|
|
|
|
|
{"hi ho", "hi ho", OsTypeLinux},
|
|
|
|
|
{"\"hi ho\" sucker", "'hi ho' sucker", OsTypeLinux},
|
|
|
|
|
{"\"hi\\\"ho\" sucker", "'hi\"ho' sucker", OsTypeLinux},
|
|
|
|
|
{"\"hi'ho\" sucker", "'hi'\\''ho' sucker", OsTypeLinux},
|
|
|
|
|
{"'hi ho' sucker", "'hi ho' sucker", OsTypeLinux},
|
|
|
|
|
{"\\\\", "'\\'", OsTypeLinux},
|
|
|
|
|
{"'\\'", "'\\'", OsTypeLinux},
|
|
|
|
|
{"hi 'null${here}too' ho", "hi 'null${here}too' ho", OsTypeLinux},
|
|
|
|
|
{"hi null${here}too ho", "hi {} ho", OsTypeLinux},
|
|
|
|
|
{"hi $(echo $dollar cent) ho", "hi {} ho", OsTypeLinux},
|
|
|
|
|
{"hi `echo $dollar \\`echo cent\\` | cat` ho", "hi {} ho", OsTypeLinux},
|
|
|
|
|
{"echo hello | more", "echo hello", OsTypeLinux},
|
|
|
|
|
{"echo hello| more", "echo hello", OsTypeLinux},
|
2010-10-14 18:05:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++)
|
|
|
|
|
QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
|
2014-02-05 10:43:21 +01:00
|
|
|
<< QString::fromLatin1(vals[i].out)
|
|
|
|
|
<< vals[i].os;
|
2010-10-14 18:05:43 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::iterations()
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(QString, in);
|
|
|
|
|
QFETCH(QString, out);
|
2014-02-05 10:43:21 +01:00
|
|
|
QFETCH(OsType, os);
|
2010-10-14 18:05:43 +02:00
|
|
|
|
|
|
|
|
QString outstr;
|
2021-05-06 13:07:36 +02:00
|
|
|
for (ProcessArgs::ArgIterator ait(&in, os); ait.next(); ) {
|
2010-10-14 18:05:43 +02:00
|
|
|
if (ait.isSimple())
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::addArg(&outstr, ait.value(), os);
|
2010-10-14 18:05:43 +02:00
|
|
|
else
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::addArgs(&outstr, "{}");
|
2014-02-05 10:43:21 +01:00
|
|
|
}
|
2010-10-14 18:05:43 +02:00
|
|
|
QCOMPARE(outstr, out);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::iteratorEditsHelper(OsType osType)
|
2010-10-14 18:05:43 +02:00
|
|
|
{
|
|
|
|
|
QString in1 = "one two three", in2 = in1, in3 = in1, in4 = in1, in5 = in1;
|
|
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::ArgIterator ait1(&in1, osType);
|
2010-10-14 18:05:43 +02:00
|
|
|
QVERIFY(ait1.next());
|
|
|
|
|
ait1.deleteArg();
|
|
|
|
|
QVERIFY(ait1.next());
|
|
|
|
|
QVERIFY(ait1.next());
|
|
|
|
|
QVERIFY(!ait1.next());
|
|
|
|
|
QCOMPARE(in1, QString::fromLatin1("two three"));
|
|
|
|
|
ait1.appendArg("four");
|
|
|
|
|
QCOMPARE(in1, QString::fromLatin1("two three four"));
|
|
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::ArgIterator ait2(&in2, osType);
|
2010-10-14 18:05:43 +02:00
|
|
|
QVERIFY(ait2.next());
|
|
|
|
|
QVERIFY(ait2.next());
|
|
|
|
|
ait2.deleteArg();
|
|
|
|
|
QVERIFY(ait2.next());
|
|
|
|
|
ait2.appendArg("four");
|
|
|
|
|
QVERIFY(!ait2.next());
|
|
|
|
|
QCOMPARE(in2, QString::fromLatin1("one three four"));
|
|
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::ArgIterator ait3(&in3, osType);
|
2010-10-14 18:05:43 +02:00
|
|
|
QVERIFY(ait3.next());
|
|
|
|
|
ait3.appendArg("one-b");
|
|
|
|
|
QVERIFY(ait3.next());
|
|
|
|
|
QVERIFY(ait3.next());
|
|
|
|
|
ait3.deleteArg();
|
|
|
|
|
QVERIFY(!ait3.next());
|
|
|
|
|
QCOMPARE(in3, QString::fromLatin1("one one-b two"));
|
|
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::ArgIterator ait4(&in4, osType);
|
2010-10-14 18:05:43 +02:00
|
|
|
ait4.appendArg("pre-one");
|
|
|
|
|
QVERIFY(ait4.next());
|
|
|
|
|
QVERIFY(ait4.next());
|
|
|
|
|
QVERIFY(ait4.next());
|
|
|
|
|
ait4.deleteArg();
|
|
|
|
|
QVERIFY(!ait4.next());
|
|
|
|
|
QCOMPARE(in4, QString::fromLatin1("pre-one one two"));
|
|
|
|
|
|
2021-05-06 13:07:36 +02:00
|
|
|
ProcessArgs::ArgIterator ait5(&in5, osType);
|
2010-10-14 18:05:43 +02:00
|
|
|
QVERIFY(ait5.next());
|
|
|
|
|
QVERIFY(ait5.next());
|
|
|
|
|
QVERIFY(ait5.next());
|
|
|
|
|
QVERIFY(!ait5.next());
|
|
|
|
|
ait5.deleteArg();
|
|
|
|
|
QVERIFY(!ait5.next());
|
|
|
|
|
QCOMPARE(in5, QString::fromLatin1("one two"));
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::iteratorEditsWindows()
|
2014-02-05 10:43:21 +01:00
|
|
|
{
|
|
|
|
|
iteratorEditsHelper(OsTypeWindows);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::iteratorEditsLinux()
|
2014-02-05 10:43:21 +01:00
|
|
|
{
|
|
|
|
|
iteratorEditsHelper(OsTypeLinux);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::exitCode_data()
|
2021-05-26 18:45:49 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<int>("exitCode");
|
|
|
|
|
|
|
|
|
|
static const auto exitCodes = {
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
"99999999", "-255", "-1",
|
|
|
|
|
#endif // Q_OS_WIN
|
|
|
|
|
"0", "1", "255"
|
|
|
|
|
};
|
|
|
|
|
for (auto exitCode : exitCodes)
|
|
|
|
|
QTest::newRow(exitCode) << QString::fromLatin1(exitCode).toInt();
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::exitCode()
|
2021-05-26 18:45:49 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(int, exitCode);
|
|
|
|
|
|
2022-04-01 14:15:30 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::ExitCode::envVar(), QString::number(exitCode));
|
2021-05-26 18:45:49 +02:00
|
|
|
{
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-04 17:14:13 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
process.start();
|
|
|
|
|
const bool finished = process.waitForFinished();
|
2021-05-26 18:45:49 +02:00
|
|
|
|
|
|
|
|
QVERIFY(finished);
|
2022-03-04 17:14:13 +01:00
|
|
|
QCOMPARE(process.exitCode(), exitCode);
|
|
|
|
|
QCOMPARE(process.exitCode() == 0, process.result() == ProcessResult::FinishedWithSuccess);
|
2021-05-26 18:45:49 +02:00
|
|
|
}
|
|
|
|
|
{
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-04 17:14:13 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
process.runBlocking();
|
2021-05-26 18:45:49 +02:00
|
|
|
|
2022-03-04 17:14:13 +01:00
|
|
|
QCOMPARE(process.exitCode(), exitCode);
|
|
|
|
|
QCOMPARE(process.exitCode() == 0, process.result() == ProcessResult::FinishedWithSuccess);
|
2021-05-26 18:45:49 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::runBlockingStdOut_data()
|
2021-05-26 03:56:03 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<bool>("withEndl");
|
2024-01-22 17:27:24 +01:00
|
|
|
QTest::addColumn<seconds>("timeout");
|
2022-03-07 18:20:02 +01:00
|
|
|
QTest::addColumn<ProcessResult>("expectedResult");
|
2021-05-26 03:56:03 +02:00
|
|
|
|
2024-01-22 12:49:58 +01:00
|
|
|
// Canceled, since the process is killed (canceled) from the callback.
|
2024-01-30 08:50:15 +01:00
|
|
|
QTest::newRow("Short timeout with end of line") << true << 1s << ProcessResult::Canceled;
|
2022-03-07 18:20:02 +01:00
|
|
|
|
2024-01-22 12:49:58 +01:00
|
|
|
// Canceled, since it times out.
|
2024-01-30 08:50:15 +01:00
|
|
|
QTest::newRow("Short timeout without end of line") << false << 1s << ProcessResult::Canceled;
|
2022-03-07 18:20:02 +01:00
|
|
|
|
|
|
|
|
// FinishedWithSuccess, since it doesn't time out, it finishes process normally,
|
|
|
|
|
// calls the callback handler and tries to stop the process forcefully what is no-op
|
|
|
|
|
// at this point in time since the process is already finished.
|
|
|
|
|
QTest::newRow("Long timeout without end of line")
|
2024-01-30 08:50:15 +01:00
|
|
|
<< false << 10s << ProcessResult::FinishedWithSuccess;
|
2022-03-14 10:31:34 +01:00
|
|
|
}
|
2021-05-26 03:56:03 +02:00
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::runBlockingStdOut()
|
2021-05-26 03:56:03 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(bool, withEndl);
|
2024-01-22 17:27:24 +01:00
|
|
|
QFETCH(seconds, timeout);
|
2022-03-07 18:20:02 +01:00
|
|
|
QFETCH(ProcessResult, expectedResult);
|
2021-05-26 03:56:03 +02:00
|
|
|
|
2022-04-01 14:15:30 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::RunBlockingStdOut::envVar(), withEndl ? "true" : "false");
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-04 17:14:13 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
2021-05-26 03:56:03 +02:00
|
|
|
bool readLastLine = false;
|
2022-03-04 17:14:13 +01:00
|
|
|
process.setStdOutCallback([&readLastLine, &process](const QString &out) {
|
2024-01-30 08:50:15 +01:00
|
|
|
if (out.contains(s_runBlockingStdOutSubProcessMagicWord)) {
|
2021-05-26 03:56:03 +02:00
|
|
|
readLastLine = true;
|
2022-03-04 17:14:13 +01:00
|
|
|
process.kill();
|
2021-05-26 03:56:03 +02:00
|
|
|
}
|
|
|
|
|
});
|
2024-01-22 17:27:24 +01:00
|
|
|
process.runBlocking(timeout);
|
2021-05-26 03:56:03 +02:00
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
// See also QTCREATORBUG-25667 for why it is a bad idea to use Process::runBlocking
|
2021-05-26 03:56:03 +02:00
|
|
|
// with interactive cli tools.
|
2022-03-07 18:20:02 +01:00
|
|
|
QCOMPARE(process.result(), expectedResult);
|
2021-05-26 03:56:03 +02:00
|
|
|
QVERIFY2(readLastLine, "Last line was read.");
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::runBlockingSignal_data()
|
2022-10-07 12:05:37 +02:00
|
|
|
{
|
|
|
|
|
runBlockingStdOut_data();
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::runBlockingSignal()
|
2022-10-07 12:05:37 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(bool, withEndl);
|
2024-01-22 17:27:24 +01:00
|
|
|
QFETCH(seconds, timeout);
|
2022-10-07 12:05:37 +02:00
|
|
|
QFETCH(ProcessResult, expectedResult);
|
|
|
|
|
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::RunBlockingStdOut::envVar(), withEndl ? "true" : "false");
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-10-07 12:05:37 +02:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
|
|
|
|
bool readLastLine = false;
|
|
|
|
|
process.setTextChannelMode(Channel::Output, TextChannelMode::MultiLine);
|
2023-05-03 16:00:22 +02:00
|
|
|
connect(&process, &Process::textOnStandardOutput,
|
2022-10-07 12:05:37 +02:00
|
|
|
this, [&readLastLine, &process](const QString &out) {
|
2024-01-30 08:50:15 +01:00
|
|
|
if (out.contains(s_runBlockingStdOutSubProcessMagicWord)) {
|
2022-10-07 12:05:37 +02:00
|
|
|
readLastLine = true;
|
|
|
|
|
process.kill();
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-01-22 17:27:24 +01:00
|
|
|
process.runBlocking(timeout);
|
2022-10-07 12:05:37 +02:00
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
// See also QTCREATORBUG-25667 for why it is a bad idea to use Process::runBlocking
|
2022-10-07 12:05:37 +02:00
|
|
|
// with interactive cli tools.
|
|
|
|
|
QCOMPARE(process.result(), expectedResult);
|
|
|
|
|
QVERIFY2(readLastLine, "Last line was read.");
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::lineCallback()
|
2021-06-09 01:00:19 +02:00
|
|
|
{
|
2022-04-01 14:15:30 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::LineCallback::envVar(), {});
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-04 17:14:13 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
2022-10-07 12:05:37 +02:00
|
|
|
const QStringList lines = QString(s_lineCallbackData).split('|');
|
2021-06-09 01:00:19 +02:00
|
|
|
int lineNumber = 0;
|
2021-06-14 15:09:11 +02:00
|
|
|
process.setStdErrLineCallback([lines, &lineNumber](const QString &actual) {
|
2022-03-04 17:25:51 +01:00
|
|
|
QString expected = lines.at(lineNumber);
|
2021-06-14 15:09:11 +02:00
|
|
|
expected.replace("\r\n", "\n");
|
2022-03-04 17:25:51 +01:00
|
|
|
// Omit some initial lines generated by Qt, e.g.
|
|
|
|
|
// Warning: Ignoring WAYLAND_DISPLAY on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.
|
|
|
|
|
if (lineNumber == 0 && actual != expected)
|
|
|
|
|
return;
|
|
|
|
|
++lineNumber;
|
2021-06-09 01:00:19 +02:00
|
|
|
QCOMPARE(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
process.start();
|
|
|
|
|
process.waitForFinished();
|
2021-06-14 15:09:11 +02:00
|
|
|
QCOMPARE(lineNumber, lines.size());
|
2021-06-09 01:00:19 +02:00
|
|
|
}
|
2021-06-14 15:09:11 +02:00
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::lineSignal()
|
2022-10-07 12:05:37 +02:00
|
|
|
{
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::LineCallback::envVar(), {});
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-10-07 12:05:37 +02:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
|
|
|
|
const QStringList lines = QString(s_lineCallbackData).split('|');
|
|
|
|
|
int lineNumber = 0;
|
|
|
|
|
process.setTextChannelMode(Channel::Error, TextChannelMode::SingleLine);
|
2023-05-03 16:00:22 +02:00
|
|
|
connect(&process, &Process::textOnStandardError,
|
2022-10-07 12:05:37 +02:00
|
|
|
this, [lines, &lineNumber](const QString &actual) {
|
|
|
|
|
QString expected = lines.at(lineNumber);
|
|
|
|
|
expected.replace("\r\n", "\n");
|
|
|
|
|
// Omit some initial lines generated by Qt, e.g.
|
|
|
|
|
// Warning: Ignoring WAYLAND_DISPLAY on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.
|
|
|
|
|
if (lineNumber == 0 && actual != expected)
|
|
|
|
|
return;
|
|
|
|
|
++lineNumber;
|
|
|
|
|
QCOMPARE(actual, expected);
|
|
|
|
|
});
|
|
|
|
|
process.start();
|
|
|
|
|
process.waitForFinished();
|
|
|
|
|
QCOMPARE(lineNumber, lines.size());
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::waitForStartedAfterStarted()
|
2022-04-25 07:18:00 +02:00
|
|
|
{
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {});
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-04-25 07:18:00 +02:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
|
|
|
|
bool started = false;
|
|
|
|
|
bool waitForStartedResult = false;
|
2023-05-03 16:00:22 +02:00
|
|
|
connect(&process, &Process::started, this, [&] {
|
2022-04-25 07:18:00 +02:00
|
|
|
started = true;
|
|
|
|
|
waitForStartedResult = process.waitForStarted();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
process.start();
|
|
|
|
|
QVERIFY(process.waitForFinished());
|
|
|
|
|
QVERIFY(started);
|
|
|
|
|
QVERIFY(waitForStartedResult);
|
|
|
|
|
QVERIFY(!process.waitForStarted());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This version is using QProcess
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::waitForStartedAfterStarted2()
|
2022-04-25 07:18:00 +02:00
|
|
|
{
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {});
|
|
|
|
|
QProcess process;
|
|
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
|
|
|
|
bool started = false;
|
|
|
|
|
bool waitForStartedResult = false;
|
|
|
|
|
connect(&process, &QProcess::started, this, [&] {
|
|
|
|
|
started = true;
|
|
|
|
|
waitForStartedResult = process.waitForStarted();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
process.start();
|
|
|
|
|
QVERIFY(process.waitForFinished());
|
|
|
|
|
QVERIFY(started);
|
|
|
|
|
QVERIFY(waitForStartedResult);
|
|
|
|
|
QVERIFY(!process.waitForStarted());
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::waitForStartedAndFinished()
|
2021-08-24 18:15:54 +02:00
|
|
|
{
|
2022-04-01 14:15:30 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {});
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-04 17:14:13 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
2021-08-24 18:15:54 +02:00
|
|
|
|
|
|
|
|
process.start();
|
|
|
|
|
QThread::msleep(1000); // long enough for process to finish
|
|
|
|
|
QVERIFY(process.waitForStarted());
|
|
|
|
|
QVERIFY(process.waitForFinished());
|
|
|
|
|
QVERIFY(!process.waitForFinished());
|
|
|
|
|
QCOMPARE(process.exitCode(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 18:41:50 +02:00
|
|
|
Q_DECLARE_METATYPE(ProcessSignalType)
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::notRunningAfterStartingNonExistingProgram_data()
|
2022-06-29 18:41:50 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<ProcessSignalType>("signalType");
|
|
|
|
|
|
|
|
|
|
QTest::newRow("Started") << ProcessSignalType::Started;
|
|
|
|
|
QTest::newRow("ReadyRead") << ProcessSignalType::ReadyRead;
|
|
|
|
|
QTest::newRow("Done") << ProcessSignalType::Done;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::notRunningAfterStartingNonExistingProgram()
|
2021-08-30 16:29:08 +02:00
|
|
|
{
|
2022-06-29 18:41:50 +02:00
|
|
|
QFETCH(ProcessSignalType, signalType);
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2024-05-16 12:31:24 +02:00
|
|
|
process.setCommand(CommandLine{"there_is_a_big_chance_that_executable_with_that_name_does_not_exists"});
|
2021-08-30 16:29:08 +02:00
|
|
|
|
2022-06-22 15:17:25 +02:00
|
|
|
int doneCount = 0;
|
2023-05-03 16:00:22 +02:00
|
|
|
QObject::connect(&process, &Process::done, [&process, &doneCount]() {
|
2022-06-22 15:17:25 +02:00
|
|
|
++doneCount;
|
|
|
|
|
QCOMPARE(process.error(), QProcess::FailedToStart);
|
2021-08-30 16:29:08 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const int loopCount = 2;
|
|
|
|
|
for (int i = 0; i < loopCount; ++i) {
|
|
|
|
|
// Work on the same process instance on every iteration
|
|
|
|
|
process.start();
|
|
|
|
|
|
|
|
|
|
QElapsedTimer timer;
|
|
|
|
|
timer.start();
|
2024-01-22 18:59:10 +01:00
|
|
|
const seconds timeout = 1s;
|
2021-08-30 16:29:08 +02:00
|
|
|
|
2022-06-29 18:41:50 +02:00
|
|
|
switch (signalType) {
|
2024-01-22 18:59:10 +01:00
|
|
|
case ProcessSignalType::Started: QVERIFY(!process.waitForStarted(timeout)); break;
|
|
|
|
|
case ProcessSignalType::ReadyRead: QVERIFY(!process.waitForReadyRead(timeout)); break;
|
|
|
|
|
case ProcessSignalType::Done: QVERIFY(!process.waitForFinished(timeout)); break;
|
2022-06-29 18:41:50 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-22 18:59:10 +01:00
|
|
|
// shouldn't wait, should finish immediately
|
|
|
|
|
QVERIFY(timer.elapsed() < duration_cast<milliseconds>(timeout).count());
|
2021-08-30 16:29:08 +02:00
|
|
|
QCOMPARE(process.state(), QProcess::NotRunning);
|
2021-09-02 16:38:40 +02:00
|
|
|
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(process.error(), QProcess::FailedToStart);
|
2021-08-30 16:29:08 +02:00
|
|
|
QVERIFY(process.exitCode() != 0);
|
2022-04-14 08:50:16 +02:00
|
|
|
QCOMPARE(process.result(), ProcessResult::StartFailed);
|
2021-08-30 16:29:08 +02:00
|
|
|
}
|
2022-06-22 15:17:25 +02:00
|
|
|
QCOMPARE(doneCount, loopCount);
|
2021-08-30 16:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
2022-03-04 17:14:13 +01:00
|
|
|
// Since we want to test whether the process forwards its channels or not, we can't just create
|
|
|
|
|
// a process and start it, because in this case there is no way on how to check whether something
|
|
|
|
|
// went into our output channels or not.
|
|
|
|
|
|
2022-04-01 08:48:00 +02:00
|
|
|
// So we start two processes in chain instead. On the beginning the channelForwarding()
|
|
|
|
|
// test starts the ChannelForwarding::main() - this one will start another process
|
2022-03-30 11:14:48 +02:00
|
|
|
// StandardOutputAndErrorWriter::main() with forwarding options.
|
|
|
|
|
// The StandardOutputAndErrorWriter::main() is very simple - it just puts something to the output
|
2022-04-01 08:48:00 +02:00
|
|
|
// and the error channels. Then ChannelForwarding::main() either forwards these channels
|
|
|
|
|
// or not - we check it in the outer channelForwarding() test.
|
2022-03-04 17:14:13 +01:00
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::channelForwarding_data()
|
2021-09-02 12:58:33 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<QProcess::ProcessChannelMode>("channelMode");
|
|
|
|
|
QTest::addColumn<bool>("outputForwarded");
|
|
|
|
|
QTest::addColumn<bool>("errorForwarded");
|
|
|
|
|
|
|
|
|
|
QTest::newRow("SeparateChannels") << QProcess::SeparateChannels << false << false;
|
2022-03-30 11:14:48 +02:00
|
|
|
QTest::newRow("MergedChannels") << QProcess::MergedChannels << false << false;
|
2021-09-02 12:58:33 +02:00
|
|
|
QTest::newRow("ForwardedChannels") << QProcess::ForwardedChannels << true << true;
|
|
|
|
|
QTest::newRow("ForwardedOutputChannel") << QProcess::ForwardedOutputChannel << true << false;
|
|
|
|
|
QTest::newRow("ForwardedErrorChannel") << QProcess::ForwardedErrorChannel << false << true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::channelForwarding()
|
2021-09-02 12:58:33 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(QProcess::ProcessChannelMode, channelMode);
|
|
|
|
|
QFETCH(bool, outputForwarded);
|
|
|
|
|
QFETCH(bool, errorForwarded);
|
|
|
|
|
|
2022-04-01 14:15:30 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::ChannelForwarding::envVar(),
|
|
|
|
|
QString::number(int(channelMode)));
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-04 17:14:13 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
2021-09-02 12:58:33 +02:00
|
|
|
|
|
|
|
|
process.start();
|
|
|
|
|
QVERIFY(process.waitForFinished());
|
|
|
|
|
|
2024-01-21 17:17:46 +01:00
|
|
|
const QByteArray output = process.rawStdOut();
|
|
|
|
|
const QByteArray error = process.rawStdErr();
|
2021-09-02 12:58:33 +02:00
|
|
|
|
2022-03-30 11:14:48 +02:00
|
|
|
QCOMPARE(output.contains(QByteArray(s_outputData)), outputForwarded);
|
|
|
|
|
QCOMPARE(error.contains(QByteArray(s_errorData)), errorForwarded);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::mergedChannels_data()
|
2022-03-30 11:14:48 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<QProcess::ProcessChannelMode>("channelMode");
|
|
|
|
|
QTest::addColumn<bool>("outputOnOutput");
|
|
|
|
|
QTest::addColumn<bool>("outputOnError");
|
|
|
|
|
QTest::addColumn<bool>("errorOnOutput");
|
|
|
|
|
QTest::addColumn<bool>("errorOnError");
|
|
|
|
|
|
|
|
|
|
QTest::newRow("SeparateChannels") << QProcess::SeparateChannels
|
|
|
|
|
<< true << false << false << true;
|
|
|
|
|
QTest::newRow("MergedChannels") << QProcess::MergedChannels
|
|
|
|
|
<< true << false << true << false;
|
|
|
|
|
QTest::newRow("ForwardedChannels") << QProcess::ForwardedChannels
|
|
|
|
|
<< false << false << false << false;
|
|
|
|
|
QTest::newRow("ForwardedOutputChannel") << QProcess::ForwardedOutputChannel
|
|
|
|
|
<< false << false << false << true;
|
|
|
|
|
QTest::newRow("ForwardedErrorChannel") << QProcess::ForwardedErrorChannel
|
|
|
|
|
<< true << false << false << false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::mergedChannels()
|
2022-03-30 11:14:48 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(QProcess::ProcessChannelMode, channelMode);
|
|
|
|
|
QFETCH(bool, outputOnOutput);
|
|
|
|
|
QFETCH(bool, outputOnError);
|
|
|
|
|
QFETCH(bool, errorOnOutput);
|
|
|
|
|
QFETCH(bool, errorOnError);
|
|
|
|
|
|
2022-04-01 14:15:30 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::StandardOutputAndErrorWriter::envVar(), {});
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-30 11:14:48 +02:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
|
|
|
|
process.setProcessChannelMode(channelMode);
|
|
|
|
|
process.start();
|
|
|
|
|
QVERIFY(process.waitForFinished());
|
|
|
|
|
|
2023-01-05 17:55:04 +01:00
|
|
|
const QByteArray output = process.readAllRawStandardOutput();
|
|
|
|
|
const QByteArray error = process.readAllRawStandardError();
|
2022-03-30 11:14:48 +02:00
|
|
|
|
|
|
|
|
QCOMPARE(output.contains(QByteArray(s_outputData)), outputOnOutput);
|
|
|
|
|
QCOMPARE(error.contains(QByteArray(s_outputData)), outputOnError);
|
|
|
|
|
QCOMPARE(output.contains(QByteArray(s_errorData)), errorOnOutput);
|
|
|
|
|
QCOMPARE(error.contains(QByteArray(s_errorData)), errorOnError);
|
2021-09-02 12:58:33 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::destroyBlockingProcess_data()
|
2022-03-08 00:28:34 +01:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<BlockType>("blockType");
|
|
|
|
|
|
|
|
|
|
QTest::newRow("EndlessLoop") << BlockType::EndlessLoop;
|
|
|
|
|
QTest::newRow("InfiniteSleep") << BlockType::InfiniteSleep;
|
|
|
|
|
QTest::newRow("MutexDeadlock") << BlockType::MutexDeadlock;
|
|
|
|
|
QTest::newRow("EventLoop") << BlockType::EventLoop;
|
2022-03-04 17:14:13 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::destroyBlockingProcess()
|
2021-08-26 16:57:52 +02:00
|
|
|
{
|
2022-03-08 00:28:34 +01:00
|
|
|
QFETCH(BlockType, blockType);
|
|
|
|
|
|
2022-06-03 11:12:29 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::BlockingProcess::envVar(),
|
2022-04-01 14:15:30 +02:00
|
|
|
QString::number(int(blockType)));
|
2021-08-26 16:57:52 +02:00
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-21 18:02:53 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
process.start();
|
|
|
|
|
QVERIFY(process.waitForStarted());
|
2023-08-10 11:10:57 +02:00
|
|
|
QVERIFY(process.isRunning());
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(!process.waitForFinished(1s));
|
2021-08-26 16:57:52 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-06 13:10:05 +01:00
|
|
|
void tst_Process::flushFinishedWhileWaitingForReadyRead_data()
|
|
|
|
|
{
|
|
|
|
|
QTest::addColumn<QProcess::ProcessChannel>("processChannel");
|
|
|
|
|
QTest::addColumn<QByteArray>("expectedData");
|
|
|
|
|
|
|
|
|
|
QTest::newRow("StandardOutput") << QProcess::StandardOutput << QByteArray(s_outputData);
|
|
|
|
|
QTest::newRow("StandardError") << QProcess::StandardError << QByteArray(s_errorData);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::flushFinishedWhileWaitingForReadyRead()
|
2021-11-04 10:27:08 +01:00
|
|
|
{
|
2023-12-06 13:10:05 +01:00
|
|
|
QFETCH(QProcess::ProcessChannel, processChannel);
|
|
|
|
|
QFETCH(QByteArray, expectedData);
|
|
|
|
|
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(),
|
|
|
|
|
QString::number(int(processChannel)));
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-04 17:14:13 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
2021-11-04 10:27:08 +01:00
|
|
|
|
|
|
|
|
process.start();
|
|
|
|
|
|
|
|
|
|
QVERIFY(process.waitForStarted());
|
|
|
|
|
QCOMPARE(process.state(), QProcess::Running);
|
|
|
|
|
|
|
|
|
|
QByteArray reply;
|
|
|
|
|
while (process.state() == QProcess::Running) {
|
2024-01-29 19:11:23 +01:00
|
|
|
process.waitForReadyRead();
|
2023-12-06 13:10:05 +01:00
|
|
|
if (processChannel == QProcess::StandardOutput)
|
|
|
|
|
reply += process.readAllRawStandardOutput();
|
|
|
|
|
else
|
|
|
|
|
reply += process.readAllRawStandardError();
|
2021-11-04 10:27:08 +01:00
|
|
|
}
|
2023-12-06 13:10:05 +01:00
|
|
|
QVERIFY(reply.contains(expectedData));
|
2021-11-04 10:27:08 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::crash()
|
2022-03-15 14:41:28 +01:00
|
|
|
{
|
2022-06-22 15:17:25 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::Crash::envVar(), {});
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-15 14:41:28 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
|
|
|
|
process.start();
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(process.waitForStarted(1s));
|
2022-06-22 15:17:25 +02:00
|
|
|
QVERIFY(process.isRunning());
|
2022-03-15 14:41:28 +01:00
|
|
|
|
|
|
|
|
QEventLoop loop;
|
2023-05-03 16:00:22 +02:00
|
|
|
connect(&process, &Process::done, &loop, &QEventLoop::quit);
|
2022-03-15 14:41:28 +01:00
|
|
|
loop.exec();
|
|
|
|
|
|
2022-03-22 12:33:03 +01:00
|
|
|
QCOMPARE(process.error(), QProcess::Crashed);
|
2022-06-22 15:17:25 +02:00
|
|
|
QCOMPARE(process.exitStatus(), QProcess::CrashExit);
|
2022-03-15 14:41:28 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::crashAfterOneSecond()
|
2022-03-21 16:24:22 +01:00
|
|
|
{
|
2022-04-01 14:15:30 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::CrashAfterOneSecond::envVar(), {});
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-03-21 16:24:22 +01:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
|
|
|
|
process.start();
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(process.waitForStarted(1s));
|
2022-03-21 16:24:22 +01:00
|
|
|
QElapsedTimer timer;
|
|
|
|
|
timer.start();
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(process.waitForFinished(30s));
|
|
|
|
|
QVERIFY(timer.elapsed() < 30000); // in milliseconds
|
2022-03-22 12:33:03 +01:00
|
|
|
QCOMPARE(process.state(), QProcess::NotRunning);
|
|
|
|
|
QCOMPARE(process.error(), QProcess::Crashed);
|
2022-03-21 16:24:22 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::recursiveCrashingProcess()
|
2022-04-01 15:02:23 +02:00
|
|
|
{
|
2022-04-01 15:14:05 +02:00
|
|
|
const int recursionDepth = 5; // must be at least 2
|
2022-04-01 15:02:23 +02:00
|
|
|
SubProcessConfig subConfig(ProcessTestApp::RecursiveCrashingProcess::envVar(),
|
|
|
|
|
QString::number(recursionDepth));
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2022-04-01 15:02:23 +02:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
process.start();
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(process.waitForStarted(1s));
|
2022-07-12 09:45:58 +02:00
|
|
|
QVERIFY(process.waitForFinished());
|
2022-04-01 15:02:23 +02:00
|
|
|
QCOMPARE(process.state(), QProcess::NotRunning);
|
|
|
|
|
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(process.exitCode(), s_crashCode);
|
|
|
|
|
}
|
2022-04-01 15:14:05 +02:00
|
|
|
|
|
|
|
|
static int runningTestProcessCount()
|
|
|
|
|
{
|
|
|
|
|
int testProcessCounter = 0;
|
|
|
|
|
const QList<ProcessInfo> processInfoList = ProcessInfo::processInfoList();
|
|
|
|
|
for (const ProcessInfo &processInfo : processInfoList) {
|
|
|
|
|
if (FilePath::fromString(processInfo.executable).baseName() == "processtestapp")
|
|
|
|
|
++testProcessCounter;
|
|
|
|
|
}
|
|
|
|
|
return testProcessCounter;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::recursiveBlockingProcess()
|
2022-04-01 15:14:05 +02:00
|
|
|
{
|
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
2022-06-03 11:12:29 +02:00
|
|
|
QSKIP(s_skipTerminateOnWindows);
|
2022-04-01 15:14:05 +02:00
|
|
|
|
2024-11-01 12:46:18 +01:00
|
|
|
ProcessReaper::deleteAll();
|
2022-04-01 15:14:05 +02:00
|
|
|
QCOMPARE(runningTestProcessCount(), 0);
|
|
|
|
|
const int recursionDepth = 5; // must be at least 2
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::RecursiveBlockingProcess::envVar(),
|
|
|
|
|
QString::number(recursionDepth));
|
|
|
|
|
{
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2023-11-06 21:00:53 +01:00
|
|
|
QSignalSpy readSpy(&process, &Process::readyReadStandardOutput);
|
|
|
|
|
QSignalSpy doneSpy(&process, &Process::done);
|
2022-04-01 15:14:05 +02:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
process.start();
|
2023-11-06 21:00:53 +01:00
|
|
|
QTRY_COMPARE(readSpy.count(), 1); // Wait until 1st ready read signal comes.
|
2023-01-05 17:55:04 +01:00
|
|
|
QCOMPARE(process.readAllRawStandardOutput(), s_leafProcessStarted);
|
2022-04-01 15:14:05 +02:00
|
|
|
QCOMPARE(runningTestProcessCount(), recursionDepth);
|
2023-11-06 21:00:53 +01:00
|
|
|
QCOMPARE(doneSpy.count(), 0);
|
2022-04-01 15:14:05 +02:00
|
|
|
process.terminate();
|
2023-11-06 21:00:53 +01:00
|
|
|
QTRY_COMPARE(readSpy.count(), 2); // Wait until 2nd ready read signal comes.
|
2023-01-05 17:55:04 +01:00
|
|
|
QCOMPARE(process.readAllRawStandardOutput(), s_leafProcessTerminated);
|
2023-11-06 21:00:53 +01:00
|
|
|
QTRY_COMPARE(doneSpy.count(), 1); // Wait until done signal comes.
|
2022-04-01 15:14:05 +02:00
|
|
|
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(process.exitCode(), s_crashCode);
|
|
|
|
|
}
|
2024-11-01 12:46:18 +01:00
|
|
|
ProcessReaper::deleteAll();
|
2022-04-01 15:14:05 +02:00
|
|
|
QCOMPARE(runningTestProcessCount(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-03 11:12:29 +02:00
|
|
|
enum class QuitType {
|
|
|
|
|
Terminate,
|
|
|
|
|
Kill,
|
|
|
|
|
Stop,
|
|
|
|
|
Close
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Q_DECLARE_METATYPE(QuitType)
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::quitBlockingProcess_data()
|
2022-06-03 11:12:29 +02:00
|
|
|
{
|
|
|
|
|
QTest::addColumn<QuitType>("quitType");
|
|
|
|
|
QTest::addColumn<bool>("doneExpected");
|
|
|
|
|
QTest::addColumn<bool>("gracefulQuit");
|
|
|
|
|
|
|
|
|
|
QTest::newRow("Terminate") << QuitType::Terminate << true << true;
|
|
|
|
|
QTest::newRow("Kill") << QuitType::Kill << true << false;
|
|
|
|
|
QTest::newRow("Stop") << QuitType::Stop << true << true;
|
|
|
|
|
QTest::newRow("Close") << QuitType::Close << false << true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::quitBlockingProcess()
|
2022-06-03 11:12:29 +02:00
|
|
|
{
|
|
|
|
|
QFETCH(QuitType, quitType);
|
|
|
|
|
QFETCH(bool, doneExpected);
|
|
|
|
|
QFETCH(bool, gracefulQuit);
|
|
|
|
|
|
|
|
|
|
if (HostOsInfo::isWindowsHost() && quitType == QuitType::Terminate)
|
|
|
|
|
QSKIP(s_skipTerminateOnWindows);
|
|
|
|
|
|
|
|
|
|
const int recursionDepth = 1;
|
|
|
|
|
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::RecursiveBlockingProcess::envVar(),
|
|
|
|
|
QString::number(recursionDepth));
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
Process process;
|
2023-11-06 21:00:53 +01:00
|
|
|
QSignalSpy readSpy(&process, &Process::readyReadStandardOutput);
|
|
|
|
|
QSignalSpy doneSpy(&process, &Process::done);
|
2022-06-03 11:12:29 +02:00
|
|
|
subConfig.setupSubProcess(&process);
|
|
|
|
|
|
|
|
|
|
process.start();
|
|
|
|
|
QVERIFY(process.waitForStarted());
|
2023-11-06 21:00:53 +01:00
|
|
|
QCOMPARE(doneSpy.count(), 0);
|
2022-06-03 11:12:29 +02:00
|
|
|
QVERIFY(process.isRunning());
|
|
|
|
|
|
2023-11-06 21:00:53 +01:00
|
|
|
QTRY_COMPARE(readSpy.count(), 1); // Wait until ready read signal comes.
|
2023-01-05 17:55:04 +01:00
|
|
|
QCOMPARE(process.readAllRawStandardOutput(), s_leafProcessStarted);
|
2022-06-03 11:12:29 +02:00
|
|
|
|
|
|
|
|
switch (quitType) {
|
|
|
|
|
case QuitType::Terminate: process.terminate(); break;
|
|
|
|
|
case QuitType::Kill: process.kill(); break;
|
|
|
|
|
case QuitType::Stop: process.stop(); break;
|
|
|
|
|
case QuitType::Close: process.close(); break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-06 21:00:53 +01:00
|
|
|
QCOMPARE(doneSpy.count(), 0);
|
2022-06-03 11:12:29 +02:00
|
|
|
|
|
|
|
|
if (doneExpected) {
|
|
|
|
|
QVERIFY(process.isRunning());
|
|
|
|
|
|
|
|
|
|
QVERIFY(process.waitForFinished());
|
|
|
|
|
|
|
|
|
|
QVERIFY(!process.isRunning());
|
2023-11-06 21:00:53 +01:00
|
|
|
QCOMPARE(doneSpy.count(), 1);
|
2022-06-03 11:12:29 +02:00
|
|
|
|
|
|
|
|
if (gracefulQuit) {
|
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
|
QSKIP(s_skipTerminateOnWindows);
|
2023-01-05 17:55:04 +01:00
|
|
|
QCOMPARE(process.readAllRawStandardOutput(), s_leafProcessTerminated);
|
2022-06-03 11:12:29 +02:00
|
|
|
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
|
|
|
|
|
QCOMPARE(process.exitCode(), s_crashCode);
|
|
|
|
|
} else {
|
2023-01-05 17:55:04 +01:00
|
|
|
QCOMPARE(process.readAllRawStandardOutput(), QByteArray());
|
2022-06-03 11:12:29 +02:00
|
|
|
QCOMPARE(process.exitStatus(), QProcess::CrashExit);
|
|
|
|
|
QVERIFY(process.exitCode() != s_crashCode);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
QVERIFY(!process.isRunning());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
void tst_Process::tarPipe()
|
2023-01-23 13:14:35 +01:00
|
|
|
{
|
|
|
|
|
if (!FilePath::fromString("tar").searchInPath().isExecutableFile())
|
|
|
|
|
QSKIP("This test uses \"tar\" command.");
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
Process sourceProcess;
|
|
|
|
|
Process targetProcess;
|
2023-01-23 13:14:35 +01:00
|
|
|
|
|
|
|
|
targetProcess.setProcessMode(ProcessMode::Writer);
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
QObject::connect(&sourceProcess, &Process::readyReadStandardOutput,
|
2023-01-23 13:14:35 +01:00
|
|
|
&targetProcess, [&sourceProcess, &targetProcess]() {
|
|
|
|
|
targetProcess.writeRaw(sourceProcess.readAllRawStandardOutput());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
QTemporaryDir sourceDir;
|
|
|
|
|
QVERIFY(sourceDir.isValid());
|
|
|
|
|
QTemporaryDir destinationDir;
|
|
|
|
|
QVERIFY(destinationDir.isValid());
|
|
|
|
|
|
|
|
|
|
const FilePath sourcePath = FilePath::fromString(sourceDir.path());
|
|
|
|
|
const FilePath sourceArchive = sourcePath / "archive";
|
|
|
|
|
QVERIFY(sourceArchive.createDir());
|
|
|
|
|
const FilePath sourceFile = sourceArchive / "file1.txt";
|
|
|
|
|
QVERIFY(sourceFile.writeFileContents("bla bla"));
|
|
|
|
|
|
|
|
|
|
const FilePath destinationPath = FilePath::fromString(destinationDir.path());
|
|
|
|
|
const FilePath destinationArchive = destinationPath / "archive";
|
|
|
|
|
const FilePath destinationFile = destinationArchive / "file1.txt";
|
|
|
|
|
|
|
|
|
|
QVERIFY(!destinationArchive.exists());
|
|
|
|
|
QVERIFY(!destinationFile.exists());
|
|
|
|
|
|
|
|
|
|
sourceProcess.setCommand({"tar", {"cvf", "-", "-C", sourcePath.nativePath(), "."}});
|
|
|
|
|
targetProcess.setCommand({"tar", {"xvf", "-", "-C", destinationPath.nativePath()}});
|
|
|
|
|
|
|
|
|
|
targetProcess.start();
|
|
|
|
|
QVERIFY(targetProcess.waitForStarted());
|
|
|
|
|
|
|
|
|
|
sourceProcess.start();
|
|
|
|
|
QVERIFY(sourceProcess.waitForFinished());
|
|
|
|
|
|
|
|
|
|
if (targetProcess.isRunning()) {
|
|
|
|
|
targetProcess.closeWriteChannel();
|
2024-01-22 18:59:10 +01:00
|
|
|
QVERIFY(targetProcess.waitForFinished(2s));
|
2023-01-23 13:14:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QCOMPARE(targetProcess.exitCode(), 0);
|
|
|
|
|
QCOMPARE(targetProcess.result(), ProcessResult::FinishedWithSuccess);
|
|
|
|
|
QVERIFY(destinationArchive.exists());
|
|
|
|
|
QVERIFY(destinationFile.exists());
|
|
|
|
|
QCOMPARE(sourceFile.fileSize(), destinationFile.fileSize());
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-14 10:00:08 +02:00
|
|
|
void tst_Process::stdinToShell()
|
|
|
|
|
{
|
|
|
|
|
// proc.setCommand({"cmd.exe", {}}); - Piping into cmd.exe does not appear to work.
|
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
|
QSKIP("Skipping env test on Windows");
|
|
|
|
|
|
|
|
|
|
Process proc;
|
2024-05-16 12:31:24 +02:00
|
|
|
proc.setCommand(CommandLine{"sh"});
|
2023-04-14 10:00:08 +02:00
|
|
|
proc.setWriteData("echo hallo");
|
|
|
|
|
proc.runBlocking();
|
|
|
|
|
|
|
|
|
|
QString result = proc.readAllStandardOutput().trimmed();
|
|
|
|
|
QCOMPARE(result, "hallo");
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-10 23:01:48 +01:00
|
|
|
void tst_Process::eventLoopMode_data()
|
|
|
|
|
{
|
|
|
|
|
QTest::addColumn<EventLoopMode>("eventLoopMode");
|
|
|
|
|
|
2024-11-01 11:56:56 +01:00
|
|
|
QTest::newRow("EventLoopMode::On") << EventLoopMode::On;
|
|
|
|
|
QTest::newRow("EventLoopMode::Off") << EventLoopMode::Off;
|
2024-01-10 23:01:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tst_Process::eventLoopMode()
|
|
|
|
|
{
|
|
|
|
|
QFETCH(EventLoopMode, eventLoopMode);
|
|
|
|
|
|
2024-01-13 03:52:59 +01:00
|
|
|
{
|
|
|
|
|
SubProcessConfig subConfig(ProcessTestApp::SimpleTest::envVar(), {});
|
|
|
|
|
Process process;
|
|
|
|
|
subConfig.setupSubProcess(&process);
|
2024-01-22 17:27:24 +01:00
|
|
|
process.runBlocking(10s, eventLoopMode);
|
2024-01-13 03:52:59 +01:00
|
|
|
QCOMPARE(process.result(), ProcessResult::FinishedWithSuccess);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
Process process;
|
2024-05-16 12:31:24 +02:00
|
|
|
process.setCommand(
|
|
|
|
|
CommandLine{"there_is_a_big_chance_that_executable_with_that_name_does_not_exists"});
|
2024-01-22 17:27:24 +01:00
|
|
|
process.runBlocking(10s, eventLoopMode);
|
2024-01-13 03:52:59 +01:00
|
|
|
QCOMPARE(process.result(), ProcessResult::StartFailed);
|
|
|
|
|
}
|
2024-01-10 23:01:48 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
QTEST_GUILESS_MAIN(tst_Process)
|
2010-10-14 18:05:43 +02:00
|
|
|
|
2023-05-04 17:20:29 +02:00
|
|
|
#include "tst_process.moc"
|