diff --git a/src/libs/utils/commandline.cpp b/src/libs/utils/commandline.cpp index 6ee998fbffb..1414a35391c 100644 --- a/src/libs/utils/commandline.cpp +++ b/src/libs/utils/commandline.cpp @@ -1490,7 +1490,7 @@ void CommandLine::addCommandLineWithAnd(const CommandLine &cmd) } addArgs("&&", Raw); - addCommandLineAsArgs(cmd); + addCommandLineAsArgs(cmd, Raw); } void CommandLine::addArgs(const QString &inArgs, RawType) diff --git a/tests/auto/utils/commandline/CMakeLists.txt b/tests/auto/utils/commandline/CMakeLists.txt index d215f5cdc6c..b839403bfee 100644 --- a/tests/auto/utils/commandline/CMakeLists.txt +++ b/tests/auto/utils/commandline/CMakeLists.txt @@ -1,4 +1,8 @@ +file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") +file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}") + add_qtc_test(tst_utils_commandline + DEFINES "TEST_RELATIVE_LIBEXEC_PATH=\"${TEST_RELATIVE_LIBEXEC_PATH}\"" DEPENDS Utils app_version SOURCES tst_commandline.cpp ) diff --git a/tests/auto/utils/commandline/tst_commandline.cpp b/tests/auto/utils/commandline/tst_commandline.cpp index 5a7202fc6a4..1845e3fa1ee 100644 --- a/tests/auto/utils/commandline/tst_commandline.cpp +++ b/tests/auto/utils/commandline/tst_commandline.cpp @@ -1,75 +1,149 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 +#include + #include +#include #include +#include +#include +#include +#include #include #include +#include + using namespace Utils; +FilePath self; + class tst_CommandLine : public QObject { Q_OBJECT private: + Environment testEnv = Environment::systemEnvironment(); + QString newLine; + + QString run(const CommandLine &cmd) + { + QtcProcess p; + p.setCommand(cmd); + p.setEnvironment(testEnv); + p.runBlocking(); + return QString::fromUtf8(p.readAllStandardOutput()); + } + private slots: - void initTestCase() {} - void cleanupTestCase() {} + void initTestCase() + { + TemporaryDirectory::setMasterTemporaryDirectory( + QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); + + const QString libExecPath(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); + LauncherInterface::setPathToLauncher(libExecPath); + + testEnv.appendOrSet("TEST_ECHO", "1"); + + if (HostOsInfo::isWindowsHost()) + newLine = "\r\n"; + else + newLine = "\n"; + } + + void cleanupTestCase() { Singleton::deleteAll(); } + + void testSpace() + { + CommandLine cmd(self, {"With Space"}); + QString expected = "With Space" + newLine; + QCOMPARE(run(cmd), expected); + } + + void testQuote() + { + QStringList args = {"\"With <\"Quote\"> % ^^ \"", "Hallo ??"}; + CommandLine cmd(self, args); + QString expected = args.join(newLine) + newLine; + QCOMPARE(run(cmd), expected); + } void testAnd() { - CommandLine cmd("echo", {"foo"}); - CommandLine cmd2("echo", {"bar", "blizz"}); + QStringList args = {"foo", "bar", "baz"}; + CommandLine cmd(self, {args[0]}); + CommandLine cmd2(self, args.sliced(1)); cmd.addCommandLineWithAnd(cmd2); - const QString actual = cmd.toUserOutput(); - const QString wanted = "echo foo && echo bar blizz"; + QString expected = args.join(newLine) + newLine; - QCOMPARE(actual, wanted); + QCOMPARE(run(cmd), expected); } void testAndComplex() { - if (HostOsInfo::isWindowsHost()) - QSKIP("CommandLine does not produce useful escaping on windows."); - - CommandLine cmd("/tmp/space path/\"echo", {"foo", "long with space"}); - CommandLine cmd2("/tmp/space \"path/echo", {"bar\"", "blizz is 'great"}); + QStringList args = {"foo", "long with space", "bar\"", "blizz is 'great"}; + CommandLine cmd(self, args.sliced(0, 2)); + CommandLine cmd2(self, args.sliced(2, 2)); cmd.addCommandLineWithAnd(cmd2); - - const QString actual = cmd.toUserOutput(); - const QString wanted = - "/tmp/space path/\"echo foo 'long with space' && '/tmp/space \"path/echo' " - "'bar\"' 'blizz is '\\''great'"; - - QCOMPARE(actual, wanted); + QString expected = args.join(newLine) + newLine; + QString actual = run(cmd); + QCOMPARE(actual, expected); } void testAndAdd() { if (HostOsInfo::isWindowsHost()) - QSKIP("CommandLine does not produce useful escaping on windows."); + QSKIP("The test does not yet work on Windows."); + + QStringList args = {"foo", "long with space", "bar", "blizz is great"}; + + CommandLine cmd(self, args.sliced(0, 2)); + CommandLine cmd2(self, args.sliced(2, 2)); - CommandLine cmd("/tmp/space path/\"echo", {"foo", "long with space"}); - CommandLine cmd2("/tmp/space \"path/echo", {"bar\"", "blizz is 'great"}); cmd.addCommandLineWithAnd(cmd2); - CommandLine shell("bash", {"-c"}); + CommandLine shell; + if (HostOsInfo::isWindowsHost()) { + shell.setExecutable(FilePath::fromUserInput(qEnvironmentVariable("COMSPEC"))); + shell.addArgs({"/v:off", "/s", "/c"}); + } else { + shell.setExecutable(FilePath::fromUserInput("/bin/sh")); + shell.addArgs({"-c"}); + } + shell.addCommandLineAsSingleArg(cmd); - const QString actual = shell.toUserOutput(); - const QString wanted = - "bash -c ''\\''/tmp/space path/\"echo'\\'' foo '\\''long with space'\\'' && " - "'\\''/tmp/space \"path/echo'\\'' '\\''bar\"'\\'' '\\''blizz is " - "'\\''\\'\\'''\\''great'\\'''"; - - QCOMPARE(actual, wanted); + QString expected = args.join(newLine) + newLine; + QString actual = run(shell); + QCOMPARE(actual, expected); } }; -QTEST_GUILESS_MAIN(tst_CommandLine) +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + self = FilePath::fromString(argv[0]); + + if (qEnvironmentVariableIsSet("TEST_ECHO")) { + for (int i = 1; i < argc; ++i) { + std::cout << argv[i] << std::endl; + } + return 0; + } + + TESTLIB_SELFCOVERAGE_START(tst_CommandLine) + QT_PREPEND_NAMESPACE(QTest::Internal::callInitMain)(); + + tst_CommandLine tc; + QTEST_SET_MAIN_SOURCE_PATH + return QTest::qExec(&tc, argc, argv); +} #include "tst_commandline.moc"