diff options
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 9 | ||||
-rw-r--r-- | tests/auto/corelib/io/qprocess/tst_qprocess.cpp | 93 | ||||
-rw-r--r-- | tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp | 4 |
3 files changed, 99 insertions, 7 deletions
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 91005b0b67..9f97bb7af9 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. -** Copyright (C) 2021 Intel Corporation. +** Copyright (C) 2022 Intel Corporation. ** Copyright (C) 2021 Alex Trotsenko. ** Contact: https://www.qt.io/licensing/ ** @@ -438,9 +438,10 @@ static QString resolveExecutable(const QString &program) #endif if (!program.contains(QLatin1Char('/'))) { - QString exeFilePath = QStandardPaths::findExecutable(program); - if (!exeFilePath.isEmpty()) - return exeFilePath; + // findExecutable() returns its argument if it's an absolute path, + // otherwise it searches $PATH; returns empty if not found (we handle + // that case much later) + return QStandardPaths::findExecutable(program); } return program; } diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index 63f2a816fc..80005a7284 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2020 Intel Corporation. +** Copyright (C) 2022 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -151,6 +151,8 @@ private slots: void startStopStartStopBuffers(); void processEventsInAReadyReadSlot_data(); void processEventsInAReadyReadSlot(); + void startFromCurrentWorkingDir_data(); + void startFromCurrentWorkingDir(); // keep these at the end, since they use lots of processes and sometimes // caused obscure failures to occur in tests that followed them (esp. on the Mac) @@ -2524,5 +2526,94 @@ void tst_QProcess::processEventsInAReadyReadSlot() QVERIFY(process.waitForFinished()); } +enum class ChdirMode { + None = 0, + InParent, + InChild +}; +Q_DECLARE_METATYPE(ChdirMode) + +void tst_QProcess::startFromCurrentWorkingDir_data() +{ + qRegisterMetaType<ChdirMode>(); + QTest::addColumn<QString>("programPrefix"); + QTest::addColumn<ChdirMode>("chdirMode"); + QTest::addColumn<bool>("success"); + + constexpr bool IsWindows = true +#ifdef Q_OS_UNIX + && false +#endif + ; + + // baseline: trying to execute the directory, this can't possibly succeed! + QTest::newRow("plain-same-cwd") << QString() << ChdirMode::None << false; + + // cross-platform behavior: neither OS searches the setWorkingDirectory() + // dir without "./" + QTest::newRow("plain-child-chdir") << QString() << ChdirMode::InChild << false; + + // cross-platform behavior: both OSes search the parent's CWD with "./" + QTest::newRow("prefixed-parent-chdir") << "./" << ChdirMode::InParent << true; + + // opposite behaviors: Windows searches the parent's CWD and Unix searches + // the child's with "./" + QTest::newRow("prefixed-child-chdir") << "./" << ChdirMode::InChild << !IsWindows; + + // Windows searches the parent's CWD without "./" + QTest::newRow("plain-parent-chdir") << QString() << ChdirMode::InParent << IsWindows; +} + +void tst_QProcess::startFromCurrentWorkingDir() +{ + QFETCH(QString, programPrefix); + QFETCH(ChdirMode, chdirMode); + QFETCH(bool, success); + + QProcess process; + qRegisterMetaType<QProcess::ProcessError>(); + QSignalSpy errorSpy(&process, &QProcess::errorOccurred); + QVERIFY(errorSpy.isValid()); + + // both the dir name and the executable name + const QString target = QStringLiteral("testProcessNormal"); + process.setProgram(programPrefix + target); + +#ifdef Q_OS_UNIX + // Reset PATH, to be sure it doesn't contain . or the empty path. + // We can't do this on Windows because DLLs are searched in PATH + // and Windows always searches "." anyway. + auto restoreEnv = qScopeGuard([old = qgetenv("PATH")] { + qputenv("PATH", old); + }); + qputenv("PATH", "/"); +#endif + + switch (chdirMode) { + case ChdirMode::InParent: { + auto restoreCwd = qScopeGuard([old = QDir::currentPath()] { + QDir::setCurrent(old); + }); + QVERIFY(QDir::setCurrent(target)); + process.start(); + break; + } + case ChdirMode::InChild: + process.setWorkingDirectory(target); + Q_FALLTHROUGH(); + case ChdirMode::None: + process.start(); + break; + } + + QCOMPARE(process.waitForStarted(), success); + QCOMPARE(errorSpy.count(), int(!success)); + if (success) { + QVERIFY(process.waitForFinished()); + } else { + QCOMPARE(process.error(), QProcess::FailedToStart); + } +} + QTEST_MAIN(tst_QProcess) #include "tst_qprocess.moc" diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp index 09c80b817d..107c5fdb84 100644 --- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -1530,7 +1530,7 @@ void tst_QApplication::desktopSettingsAware() environment += QLatin1String("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM=1"); testProcess.setEnvironment(environment); #endif - testProcess.start("desktopsettingsaware_helper"); + testProcess.start("./desktopsettingsaware_helper"); QVERIFY2(testProcess.waitForStarted(), qPrintable(QString::fromLatin1("Cannot start 'desktopsettingsaware_helper': %1").arg(testProcess.errorString()))); QVERIFY(testProcess.waitForFinished(10000)); @@ -2470,7 +2470,7 @@ void tst_QApplication::qtbug_12673() #if QT_CONFIG(process) QProcess testProcess; QStringList arguments; - testProcess.start("modal_helper", arguments); + testProcess.start("./modal_helper", arguments); QVERIFY2(testProcess.waitForStarted(), qPrintable(QString::fromLatin1("Cannot start 'modal_helper': %1").arg(testProcess.errorString()))); QVERIFY(testProcess.waitForFinished(20000)); |