aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qtcprocess/tst_qtcprocess.cpp
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@nokia.com>2010-10-14 18:05:43 +0200
committerOswald Buddenhagen <oswald.buddenhagen@nokia.com>2010-11-17 13:19:07 +0100
commit531c70f05bfc8355f856f2af41be533fb13b85e6 (patch)
tree33d0d30107949f92e507e26f083d5d3caa98e8b8 /tests/auto/qtcprocess/tst_qtcprocess.cpp
parentdc3ab5bf85d6ce9be2131f1a299731288d37c923 (diff)
add Utils::QtcProcess
this is a wrapper around QProcess with these features: - setEnvironment() takes a Utils::Environment instead of a QStringList - instead of taking a stringlist with arguments, take a single shell command string which is fully compatible with the system's native shell (the bourne shell on unix and cmd.exe on windows) - with support for environment variable expansion, and subject to the shell's splitting and quoting rules. if the command is too complex (e.g., contains redirections), it is transparently executed through a real shell. - additionally, the class contains a set of helper functions for manipulating (constructing, splitting, etc.) shell command lines. in particular, it contains a shell-safe macro expander and the nested class ArgIterator which can be used for inspecting and manipulating a shell command line without going through the stringlist indirection (which is potentially lossy). some of this is based on KDE code (KShell and KMacroExpander) which i have written myself.
Diffstat (limited to 'tests/auto/qtcprocess/tst_qtcprocess.cpp')
-rw-r--r--tests/auto/qtcprocess/tst_qtcprocess.cpp698
1 files changed, 698 insertions, 0 deletions
diff --git a/tests/auto/qtcprocess/tst_qtcprocess.cpp b/tests/auto/qtcprocess/tst_qtcprocess.cpp
new file mode 100644
index 0000000000..a6ef552914
--- /dev/null
+++ b/tests/auto/qtcprocess/tst_qtcprocess.cpp
@@ -0,0 +1,698 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include <utils/qtcprocess.h>
+#include <utils/stringutils.h>
+#include <utils/environment.h>
+
+#include <QtTest/QtTest>
+
+using namespace Utils;
+
+class MacroMapExpander : public AbstractQtcMacroExpander {
+public:
+ virtual bool resolveMacro(const QString &name, QString *ret)
+ {
+ QHash<QString, QString>::const_iterator it = m_map.constFind(name);
+ if (it != m_map.constEnd()) {
+ *ret = it.value();
+ return true;
+ }
+ return false;
+ }
+ void insert(const QString &key, const QString &value) { m_map.insert(key, value); }
+private:
+ QHash<QString, QString> m_map;
+};
+
+class tst_QtcProcess : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void splitArgs_data();
+ void splitArgs();
+ void prepareArgs_data();
+ void prepareArgs();
+ void prepareArgsEnv_data();
+ void prepareArgsEnv();
+ void expandMacros_data();
+ void expandMacros();
+ void iterations_data();
+ void iterations();
+ void iteratorEdits();
+
+private:
+ Environment env;
+ MacroMapExpander mx;
+};
+
+void tst_QtcProcess::initTestCase()
+{
+ env.set("empty", "");
+ env.set("word", "hi");
+ env.set("words", "hi ho");
+ env.set("spacedwords", " hi ho sucker ");
+
+#ifdef Q_OS_WIN
+ mx.insert("a", "hi");
+ mx.insert("aa", "hi ho");
+
+ mx.insert("b", "h\\i");
+ mx.insert("c", "\\hi");
+ mx.insert("d", "hi\\");
+ mx.insert("ba", "h\\i ho");
+ mx.insert("ca", "\\hi ho");
+ mx.insert("da", "hi ho\\");
+
+ mx.insert("e", "h\"i");
+ mx.insert("f", "\"hi");
+ mx.insert("g", "hi\"");
+
+ mx.insert("h", "h\\\"i");
+ mx.insert("i", "\\\"hi");
+ mx.insert("j", "hi\\\"");
+
+ mx.insert("k", "&special;");
+
+ mx.insert("x", "\\");
+ mx.insert("y", "\"");
+#else
+ mx.insert("a", "hi");
+ mx.insert("b", "hi ho");
+ mx.insert("c", "&special;");
+ mx.insert("d", "h\\i");
+ mx.insert("e", "h\"i");
+ mx.insert("f", "h'i");
+#endif
+ mx.insert("z", "");
+}
+
+Q_DECLARE_METATYPE(QtcProcess::SplitError)
+
+void tst_QtcProcess::splitArgs_data()
+{
+ QTest::addColumn<QString>("in");
+ QTest::addColumn<QString>("out");
+ QTest::addColumn<QtcProcess::SplitError>("err");
+
+ static const struct {
+ const char * const in;
+ const char * const out;
+ const QtcProcess::SplitError err;
+ } vals[] = {
+#ifdef Q_OS_WIN
+ { "", "", QtcProcess::SplitOk },
+ { " ", "", QtcProcess::SplitOk },
+ { "hi", "hi", QtcProcess::SplitOk },
+ { "hi ho", "hi ho", QtcProcess::SplitOk },
+ { " hi ho ", "hi ho", QtcProcess::SplitOk },
+ { "\"hi ho\" \"hi\" ho ", "\"hi ho\" hi ho", QtcProcess::SplitOk },
+ { "\\", "\\", QtcProcess::SplitOk },
+ { "\\\"", "\"\"\\^\"\"\"", QtcProcess::SplitOk },
+ { "\"hi\"\"\"ho\"", "\"hi\"\\^\"\"ho\"", QtcProcess::SplitOk },
+ { "\\\\\\\"", "\"\"\\\\\\^\"\"\"", QtcProcess::SplitOk },
+ { " ^^ ", "\"^^\"", QtcProcess::SplitOk },
+ { "hi\"", "", QtcProcess::BadQuoting },
+ { "hi\"dood", "", QtcProcess::BadQuoting },
+ { "%var%", "%var%", QtcProcess::SplitOk },
+#else
+ { "", "", QtcProcess::SplitOk },
+ { " ", "", QtcProcess::SplitOk },
+ { "hi", "hi", QtcProcess::SplitOk },
+ { "hi ho", "hi ho", QtcProcess::SplitOk },
+ { " hi ho ", "hi ho", QtcProcess::SplitOk },
+ { "'hi ho' \"hi\" ho ", "'hi ho' hi ho", QtcProcess::SplitOk },
+ { " \\ ", "' '", QtcProcess::SplitOk },
+ { " \\\" ", "'\"'", QtcProcess::SplitOk },
+ { " '\"' ", "'\"'", QtcProcess::SplitOk },
+ { " \"\\\"\" ", "'\"'", QtcProcess::SplitOk },
+ { "hi'", "", QtcProcess::BadQuoting },
+ { "hi\"dood", "", QtcProcess::BadQuoting },
+ { "$var", "'$var'", QtcProcess::SplitOk },
+#endif
+ };
+
+ for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++)
+ QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
+ << QString::fromLatin1(vals[i].out)
+ << vals[i].err;
+}
+
+void tst_QtcProcess::splitArgs()
+{
+ QFETCH(QString, in);
+ QFETCH(QString, out);
+ QFETCH(QtcProcess::SplitError, err);
+
+ QtcProcess::SplitError outerr;
+ QString outstr = QtcProcess::joinArgs(QtcProcess::splitArgs(in, false, &outerr));
+ QCOMPARE(outerr, err);
+ if (err == QtcProcess::SplitOk)
+ QCOMPARE(outstr, out);
+}
+
+void tst_QtcProcess::prepareArgs_data()
+{
+ QTest::addColumn<QString>("in");
+ QTest::addColumn<QString>("out");
+ QTest::addColumn<QtcProcess::SplitError>("err");
+
+ static const struct {
+ const char * const in;
+ const char * const out;
+ const QtcProcess::SplitError err;
+ } vals[] = {
+#ifdef Q_OS_WIN
+ { "", "", QtcProcess::SplitOk },
+ { " ", " ", QtcProcess::SplitOk },
+ { "hi", "hi", QtcProcess::SplitOk },
+ { "hi ho", "hi ho", QtcProcess::SplitOk },
+ { " hi ho ", " hi ho ", QtcProcess::SplitOk },
+ { "\"hi ho\" \"hi\" ho ", "\"hi ho\" \"hi\" ho ", QtcProcess::SplitOk },
+ { "\\", "\\", QtcProcess::SplitOk },
+ { "\\\"", "\\\"", QtcProcess::SplitOk },
+ { "\"hi\"\"ho\"", "\"hi\"\"ho\"", QtcProcess::SplitOk },
+ { "\\\\\\\"", "\\\\\\\"", QtcProcess::SplitOk },
+ { "^^", "^", QtcProcess::SplitOk },
+ { "hi\"", "hi\"", QtcProcess::SplitOk },
+ { "hi\"dood", "hi\"dood", QtcProcess::SplitOk },
+ { "%var%", "", QtcProcess::FoundMeta },
+ { "echo hi > file", "", QtcProcess::FoundMeta },
+#else
+ { "", "", QtcProcess::SplitOk },
+ { " ", "", QtcProcess::SplitOk },
+ { "hi", "hi", QtcProcess::SplitOk },
+ { "hi ho", "hi ho", QtcProcess::SplitOk },
+ { " hi ho ", "hi ho", QtcProcess::SplitOk },
+ { "'hi ho' \"hi\" ho ", "'hi ho' hi ho", QtcProcess::SplitOk },
+ { " \\ ", "' '", QtcProcess::SplitOk },
+ { "hi'", "", QtcProcess::BadQuoting },
+ { "hi\"dood", "", QtcProcess::BadQuoting },
+ { "$var", "", QtcProcess::FoundMeta },
+#endif
+ };
+
+ for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++)
+ QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
+ << QString::fromLatin1(vals[i].out)
+ << vals[i].err;
+}
+
+void tst_QtcProcess::prepareArgs()
+{
+ QFETCH(QString, in);
+ QFETCH(QString, out);
+ QFETCH(QtcProcess::SplitError, err);
+
+ QtcProcess::SplitError outerr;
+ QString outstr;
+#ifdef Q_OS_WIN
+ outstr = QtcProcess::prepareArgs(in, &outerr);
+#else
+ outstr = QtcProcess::joinArgs(QtcProcess::prepareArgs(in, &outerr));
+#endif
+ QCOMPARE(outerr, err);
+ if (err == QtcProcess::SplitOk)
+ QCOMPARE(outstr, out);
+}
+
+void tst_QtcProcess::prepareArgsEnv_data()
+{
+ QTest::addColumn<QString>("in");
+ QTest::addColumn<QString>("out");
+ QTest::addColumn<QtcProcess::SplitError>("err");
+
+ static const struct {
+ const char * const in;
+ const char * const out;
+ const QtcProcess::SplitError err;
+ } vals[] = {
+#ifdef Q_OS_WIN
+ { "", "", QtcProcess::SplitOk },
+ { " ", " ", QtcProcess::SplitOk },
+ { "hi", "hi", QtcProcess::SplitOk },
+ { "hi ho", "hi ho", QtcProcess::SplitOk },
+ { " hi ho ", " hi ho ", QtcProcess::SplitOk },
+ { "\"hi ho\" \"hi\" ho ", "\"hi ho\" \"hi\" ho ", QtcProcess::SplitOk },
+ { "\\", "\\", QtcProcess::SplitOk },
+ { "\\\"", "\\\"", QtcProcess::SplitOk },
+ { "\"hi\"\"ho\"", "\"hi\"\"ho\"", QtcProcess::SplitOk },
+ { "\\\\\\\"", "\\\\\\\"", QtcProcess::SplitOk },
+ { "^^", "^", QtcProcess::SplitOk },
+ { "hi\"", "hi\"", QtcProcess::SplitOk },
+ { "hi\"dood", "hi\"dood", QtcProcess::SplitOk },
+ { "%empty%", "%empty%", QtcProcess::SplitOk }, // Yep, no empty variables on Windows.
+ { "%word%", "hi", QtcProcess::SplitOk },
+ { " %word% ", " hi ", QtcProcess::SplitOk },
+ { "%words%", "hi ho", QtcProcess::SplitOk },
+ { "%nonsense%words%", "%nonsensehi ho", QtcProcess::SplitOk },
+ { "fail%nonsense%words%", "fail%nonsensehi ho", QtcProcess::SplitOk },
+ { "%words%words%", "hi howords%", QtcProcess::SplitOk },
+ { "%words%%words%", "hi hohi ho", QtcProcess::SplitOk },
+ { "echo hi > file", "", QtcProcess::FoundMeta },
+#else
+ { "", "", QtcProcess::SplitOk },
+ { " ", "", QtcProcess::SplitOk },
+ { "hi", "hi", QtcProcess::SplitOk },
+ { "hi ho", "hi ho", QtcProcess::SplitOk },
+ { " hi ho ", "hi ho", QtcProcess::SplitOk },
+ { "'hi ho' \"hi\" ho ", "'hi ho' hi ho", QtcProcess::SplitOk },
+ { " \\ ", "' '", QtcProcess::SplitOk },
+ { "hi'", "", QtcProcess::BadQuoting },
+ { "hi\"dood", "", QtcProcess::BadQuoting },
+ { "$empty", "", QtcProcess::SplitOk },
+ { "$word", "hi", QtcProcess::SplitOk },
+ { " $word ", "hi", QtcProcess::SplitOk },
+ { "${word}", "hi", QtcProcess::SplitOk },
+ { " ${word} ", "hi", QtcProcess::SplitOk },
+ { "$words", "hi ho", QtcProcess::SplitOk },
+ { "$spacedwords", "hi ho sucker", QtcProcess::SplitOk },
+ { "hi${empty}ho", "hiho", QtcProcess::SplitOk },
+ { "hi${words}ho", "hihi hoho", QtcProcess::SplitOk },
+ { "hi${spacedwords}ho", "hi hi ho sucker ho", QtcProcess::SplitOk },
+ { "${", "", QtcProcess::BadQuoting },
+ { "${var", "", QtcProcess::BadQuoting },
+ { "${var ", "", QtcProcess::FoundMeta },
+ { "\"hi${words}ho\"", "'hihi hoho'", QtcProcess::SplitOk },
+ { "\"hi${spacedwords}ho\"", "'hi hi ho sucker ho'", QtcProcess::SplitOk },
+ { "\"${", "", QtcProcess::BadQuoting },
+ { "\"${var", "", QtcProcess::BadQuoting },
+ { "\"${var ", "", QtcProcess::FoundMeta },
+#endif
+ };
+
+ for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++)
+ QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
+ << QString::fromLatin1(vals[i].out)
+ << vals[i].err;
+}
+
+void tst_QtcProcess::prepareArgsEnv()
+{
+ QFETCH(QString, in);
+ QFETCH(QString, out);
+ QFETCH(QtcProcess::SplitError, err);
+
+ QtcProcess::SplitError outerr;
+ QString outstr;
+#ifdef Q_OS_WIN
+ outstr = QtcProcess::prepareArgs(in, &outerr, &env);
+#else
+ outstr = QtcProcess::joinArgs(QtcProcess::prepareArgs(in, &outerr, &env));
+#endif
+ QCOMPARE(outerr, err);
+ if (err == QtcProcess::SplitOk)
+ QCOMPARE(outstr, out);
+}
+
+void tst_QtcProcess::expandMacros_data()
+
+{
+ QTest::addColumn<QString>("in");
+ QTest::addColumn<QString>("out");
+ QChar sp(QLatin1Char(' '));
+
+ static const struct {
+ const char * const in;
+ const char * const out;
+ } vals[] = {
+#ifdef Q_OS_WIN
+ { "plain", 0 },
+ { "%{a}", "hi" },
+ { "%{aa}", "\"hi ho\"" },
+ { "%{b}", "h\\i" },
+ { "%{c}", "\\hi" },
+ { "%{d}", "hi\\" },
+ { "%{ba}", "\"h\\i ho\"" },
+ { "%{ca}", "\"\\hi ho\"" },
+ { "%{da}", "\"hi ho\\\\\"" }, // or "\"hi ho\"\\"
+ { "%{e}", "\"h\"\\^\"\"i\"" },
+ { "%{f}", "\"\"\\^\"\"hi\"" },
+ { "%{g}", "\"hi\"\\^\"\"\"" },
+ { "%{h}", "\"h\\\\\"\\^\"\"i\"" },
+ { "%{i}", "\"\\\\\"\\^\"\"hi\"" },
+ { "%{j}", "\"hi\\\\\"\\^\"\"\"" },
+ { "%{k}", "\"&special;\"" },
+ { "%{x}", "\\" },
+ { "%{y}", "\"\"\\^\"\"\"" },
+ { "%{z}", "\"\"" },
+ { "^%{z}%{z}", "^%{z}%{z}" }, // stupid user check
+
+ { "quoted", 0 },
+ { "\"%{a}\"", "\"hi\"" },
+ { "\"%{aa}\"", "\"hi ho\"" },
+ { "\"%{b}\"", "\"h\\i\"" },
+ { "\"%{c}\"", "\"\\hi\"" },
+ { "\"%{d}\"", "\"hi\\\\\"" },
+ { "\"%{ba}\"", "\"h\\i ho\"" },
+ { "\"%{ca}\"", "\"\\hi ho\"" },
+ { "\"%{da}\"", "\"hi ho\\\\\"" },
+ { "\"%{e}\"", "\"h\"\\^\"\"i\"" },
+ { "\"%{f}\"", "\"\"\\^\"\"hi\"" },
+ { "\"%{g}\"", "\"hi\"\\^\"\"\"" },
+ { "\"%{h}\"", "\"h\\\\\"\\^\"\"i\"" },
+ { "\"%{i}\"", "\"\\\\\"\\^\"\"hi\"" },
+ { "\"%{j}\"", "\"hi\\\\\"\\^\"\"\"" },
+ { "\"%{k}\"", "\"&special;\"" },
+ { "\"%{x}\"", "\"\\\\\"" },
+ { "\"%{y}\"", "\"\"\\^\"\"\"" },
+ { "\"%{z}\"", "\"\"" },
+
+ { "leading bs", 0 },
+ { "\\%{a}", "\\hi" },
+ { "\\%{aa}", "\\\\\"hi ho\"" },
+ { "\\%{b}", "\\h\\i" },
+ { "\\%{c}", "\\\\hi" },
+ { "\\%{d}", "\\hi\\" },
+ { "\\%{ba}", "\\\\\"h\\i ho\"" },
+ { "\\%{ca}", "\\\\\"\\hi ho\"" },
+ { "\\%{da}", "\\\\\"hi ho\\\\\"" },
+ { "\\%{e}", "\\\\\"h\"\\^\"\"i\"" },
+ { "\\%{f}", "\\\\\"\"\\^\"\"hi\"" },
+ { "\\%{g}", "\\\\\"hi\"\\^\"\"\"" },
+ { "\\%{h}", "\\\\\"h\\\\\"\\^\"\"i\"" },
+ { "\\%{i}", "\\\\\"\\\\\"\\^\"\"hi\"" },
+ { "\\%{j}", "\\\\\"hi\\\\\"\\^\"\"\"" },
+ { "\\%{x}", "\\\\" },
+ { "\\%{y}", "\\\\\"\"\\^\"\"\"" },
+ { "\\%{z}", "\\" },
+
+ { "trailing bs", 0 },
+ { "%{a}\\", "hi\\" },
+ { "%{aa}\\", "\"hi ho\"\\" },
+ { "%{b}\\", "h\\i\\" },
+ { "%{c}\\", "\\hi\\" },
+ { "%{d}\\", "hi\\\\" },
+ { "%{ba}\\", "\"h\\i ho\"\\" },
+ { "%{ca}\\", "\"\\hi ho\"\\" },
+ { "%{da}\\", "\"hi ho\\\\\"\\" },
+ { "%{e}\\", "\"h\"\\^\"\"i\"\\" },
+ { "%{f}\\", "\"\"\\^\"\"hi\"\\" },
+ { "%{g}\\", "\"hi\"\\^\"\"\"\\" },
+ { "%{h}\\", "\"h\\\\\"\\^\"\"i\"\\" },
+ { "%{i}\\", "\"\\\\\"\\^\"\"hi\"\\" },
+ { "%{j}\\", "\"hi\\\\\"\\^\"\"\"\\" },
+ { "%{x}\\", "\\\\" },
+ { "%{y}\\", "\"\"\\^\"\"\"\\" },
+ { "%{z}\\", "\\" },
+
+ { "bs-enclosed", 0 },
+ { "\\%{a}\\", "\\hi\\" },
+ { "\\%{aa}\\", "\\\\\"hi ho\"\\" },
+ { "\\%{b}\\", "\\h\\i\\" },
+ { "\\%{c}\\", "\\\\hi\\" },
+ { "\\%{d}\\", "\\hi\\\\" },
+ { "\\%{ba}\\", "\\\\\"h\\i ho\"\\" },
+ { "\\%{ca}\\", "\\\\\"\\hi ho\"\\" },
+ { "\\%{da}\\", "\\\\\"hi ho\\\\\"\\" },
+ { "\\%{e}\\", "\\\\\"h\"\\^\"\"i\"\\" },
+ { "\\%{f}\\", "\\\\\"\"\\^\"\"hi\"\\" },
+ { "\\%{g}\\", "\\\\\"hi\"\\^\"\"\"\\" },
+ { "\\%{h}\\", "\\\\\"h\\\\\"\\^\"\"i\"\\" },
+ { "\\%{i}\\", "\\\\\"\\\\\"\\^\"\"hi\"\\" },
+ { "\\%{j}\\", "\\\\\"hi\\\\\"\\^\"\"\"\\" },
+ { "\\%{x}\\", "\\\\\\" },
+ { "\\%{y}\\", "\\\\\"\"\\^\"\"\"\\" },
+ { "\\%{z}\\", "\\\\" },
+
+ { "bs-enclosed and trailing literal quote", 0 },
+ { "\\%{a}\\\\\\^\"", "\\hi\\\\\\^\"" },
+ { "\\%{aa}\\\\\\^\"", "\\\\\"hi ho\"\\\\\\^\"" },
+ { "\\%{b}\\\\\\^\"", "\\h\\i\\\\\\^\"" },
+ { "\\%{c}\\\\\\^\"", "\\\\hi\\\\\\^\"" },
+ { "\\%{d}\\\\\\^\"", "\\hi\\\\\\\\\\^\"" },
+ { "\\%{ba}\\\\\\^\"", "\\\\\"h\\i ho\"\\\\\\^\"" },
+ { "\\%{ca}\\\\\\^\"", "\\\\\"\\hi ho\"\\\\\\^\"" },
+ { "\\%{da}\\\\\\^\"", "\\\\\"hi ho\\\\\"\\\\\\^\"" },
+ { "\\%{e}\\\\\\^\"", "\\\\\"h\"\\^\"\"i\"\\\\\\^\"" },
+ { "\\%{f}\\\\\\^\"", "\\\\\"\"\\^\"\"hi\"\\\\\\^\"" },
+ { "\\%{g}\\\\\\^\"", "\\\\\"hi\"\\^\"\"\"\\\\\\^\"" },
+ { "\\%{h}\\\\\\^\"", "\\\\\"h\\\\\"\\^\"\"i\"\\\\\\^\"" },
+ { "\\%{i}\\\\\\^\"", "\\\\\"\\\\\"\\^\"\"hi\"\\\\\\^\"" },
+ { "\\%{j}\\\\\\^\"", "\\\\\"hi\\\\\"\\^\"\"\"\\\\\\^\"" },
+ { "\\%{x}\\\\\\^\"", "\\\\\\\\\\\\\\^\"" },
+ { "\\%{y}\\\\\\^\"", "\\\\\"\"\\^\"\"\"\\\\\\^\"" },
+ { "\\%{z}\\\\\\^\"", "\\\\\\\\\\^\"" },
+
+ { "bs-enclosed and trailing unclosed quote", 0 },
+ { "\\%{a}\\\\\"", "\\hi\\\\\"" },
+ { "\\%{aa}\\\\\"", "\\\\\"hi ho\"\\\\\"" },
+ { "\\%{b}\\\\\"", "\\h\\i\\\\\"" },
+ { "\\%{c}\\\\\"", "\\\\hi\\\\\"" },
+ { "\\%{d}\\\\\"", "\\hi\\\\\\\\\"" },
+ { "\\%{ba}\\\\\"", "\\\\\"h\\i ho\"\\\\\"" },
+ { "\\%{ca}\\\\\"", "\\\\\"\\hi ho\"\\\\\"" },
+ { "\\%{da}\\\\\"", "\\\\\"hi ho\\\\\"\\\\\"" },
+ { "\\%{e}\\\\\"", "\\\\\"h\"\\^\"\"i\"\\\\\"" },
+ { "\\%{f}\\\\\"", "\\\\\"\"\\^\"\"hi\"\\\\\"" },
+ { "\\%{g}\\\\\"", "\\\\\"hi\"\\^\"\"\"\\\\\"" },
+ { "\\%{h}\\\\\"", "\\\\\"h\\\\\"\\^\"\"i\"\\\\\"" },
+ { "\\%{i}\\\\\"", "\\\\\"\\\\\"\\^\"\"hi\"\\\\\"" },
+ { "\\%{j}\\\\\"", "\\\\\"hi\\\\\"\\^\"\"\"\\\\\"" },
+ { "\\%{x}\\\\\"", "\\\\\\\\\\\\\"" },
+ { "\\%{y}\\\\\"", "\\\\\"\"\\^\"\"\"\\\\\"" },
+ { "\\%{z}\\\\\"", "\\\\\\\\\"" },
+
+ { "multi-var", 0 },
+ { "%{x}%{y}%{z}", "\\\\\"\"\\^\"\"\"" },
+ { "%{x}%{z}%{y}%{z}", "\\\\\"\"\\^\"\"\"" },
+ { "%{x}%{z}%{y}", "\\\\\"\"\\^\"\"\"" },
+ { "%{x}\\^\"%{z}", "\\\\\\^\"" },
+ { "%{x}%{z}\\^\"%{z}", "\\\\\\^\"" },
+ { "%{x}%{z}\\^\"", "\\\\\\^\"" },
+ { "%{x}\\%{z}", "\\\\" },
+ { "%{x}%{z}\\%{z}", "\\\\" },
+ { "%{x}%{z}\\", "\\\\" },
+ { "%{aa}%{a}", "\"hi hohi\"" },
+ { "%{aa}%{aa}", "\"hi hohi ho\"" },
+ { "%{aa}:%{aa}", "\"hi ho\":\"hi ho\"" },
+ { "hallo ^|%{aa}^|", "hallo ^|\"hi ho\"^|" },
+
+ { "quoted multi-var", 0 },
+ { "\"%{x}%{y}%{z}\"", "\"\\\\\"\\^\"\"\"" },
+ { "\"%{x}%{z}%{y}%{z}\"", "\"\\\\\"\\^\"\"\"" },
+ { "\"%{x}%{z}%{y}\"", "\"\\\\\"\\^\"\"\"" },
+ { "\"%{x}\"^\"\"%{z}\"", "\"\\\\\"^\"\"\"" },
+ { "\"%{x}%{z}\"^\"\"%{z}\"", "\"\\\\\"^\"\"\"" },
+ { "\"%{x}%{z}\"^\"\"\"", "\"\\\\\"^\"\"\"" },
+ { "\"%{x}\\%{z}\"", "\"\\\\\\\\\"" },
+ { "\"%{x}%{z}\\%{z}\"", "\"\\\\\\\\\"" },
+ { "\"%{x}%{z}\\\\\"", "\"\\\\\\\\\"" },
+ { "\"%{aa}%{a}\"", "\"hi hohi\"" },
+ { "\"%{aa}%{aa}\"", "\"hi hohi ho\"" },
+ { "\"%{aa}:%{aa}\"", "\"hi ho:hi ho\"" },
+#else
+ { "plain", 0 },
+ { "%{a}", "hi" },
+ { "%{b}", "'hi ho'" },
+ { "%{c}", "'&special;'" },
+ { "%{d}", "'h\\i'" },
+ { "%{e}", "'h\"i'" },
+ { "%{f}", "'h'\\''i'" },
+ { "%{z}", "''" },
+ { "\\%{z}%{z}", "\\%{z}%{z}" }, // stupid user check
+
+ { "single-quoted", 0 },
+ { "'%{a}'", "'hi'" },
+ { "'%{b}'", "'hi ho'" },
+ { "'%{c}'", "'&special;'" },
+ { "'%{d}'", "'h\\i'" },
+ { "'%{e}'", "'h\"i'" },
+ { "'%{f}'", "'h'\\''i'" },
+ { "'%{z}'", "''" },
+
+ { "double-quoted", 0 },
+ { "\"%{a}\"", "\"hi\"" },
+ { "\"%{b}\"", "\"hi ho\"" },
+ { "\"%{c}\"", "\"&special;\"" },
+ { "\"%{d}\"", "\"h\\\\i\"" },
+ { "\"%{e}\"", "\"h\\\"i\"" },
+ { "\"%{f}\"", "\"h'i\"" },
+ { "\"%{z}\"", "\"\"" },
+
+ { "complex", 0 },
+ { "echo \"$(echo %{a})\"", "echo \"$(echo hi)\"" },
+ { "echo \"$(echo %{b})\"", "echo \"$(echo 'hi ho')\"" },
+ { "echo \"$(echo \"%{a}\")\"", "echo \"$(echo \"hi\")\"" },
+ // These make no sense shell-wise, but they test expando nesting
+ { "echo \"%{echo %{a}}\"", "echo \"%{echo hi}\"" },
+ { "echo \"%{echo %{b}}\"", "echo \"%{echo hi ho}\"" },
+ { "echo \"%{echo \"%{a}\"}\"", "echo \"%{echo \"hi\"}\"" },
+#endif
+ };
+
+ const char *title = 0;
+ for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
+ if (!vals[i].out) {
+ title = vals[i].in;
+ } else {
+ char buf[80];
+ sprintf(buf, "%s: %s", title, vals[i].in);
+ QTest::newRow(buf) << QString::fromLatin1(vals[i].in)
+ << QString::fromLatin1(vals[i].out);
+ sprintf(buf, "padded %s: %s", title, vals[i].in);
+ QTest::newRow(buf) << (sp + QString::fromLatin1(vals[i].in) + sp)
+ << (sp + QString::fromLatin1(vals[i].out) + sp);
+ }
+ }
+}
+
+void tst_QtcProcess::expandMacros()
+{
+ QFETCH(QString, in);
+ QFETCH(QString, out);
+
+ QtcProcess::expandMacros(&in, &mx);
+ QCOMPARE(in, out);
+}
+
+void tst_QtcProcess::iterations_data()
+{
+ QTest::addColumn<QString>("in");
+ QTest::addColumn<QString>("out");
+
+ static const struct {
+ const char * const in;
+ const char * const out;
+ } vals[] = {
+#ifdef Q_OS_WIN
+ { "", "" },
+ { "hi", "hi" },
+ { " hi ", "hi" },
+ { "hi ho", "hi ho" },
+ { "\"hi ho\" sucker", "\"hi ho\" sucker" },
+ { "\"hi\"^\"\"ho\" sucker", "\"hi\"\\^\"\"ho\" sucker" },
+ { "\"hi\"\\^\"\"ho\" sucker", "\"hi\"\\^\"\"ho\" sucker" },
+ { "hi^|ho", "\"hi|ho\"" },
+ { "c:\\", "c:\\" },
+ { "\"c:\\\\\"", "c:\\" },
+ { "\\hi\\ho", "\\hi\\ho" },
+ { "hi null%", "hi null%" },
+ { "hi null% ho", "hi null% ho" },
+ { "hi null%here ho", "hi null%here ho" },
+ { "hi null%here%too ho", "hi {} ho" },
+ { "echo hello | more", "echo hello" },
+ { "echo hello| more", "echo hello" },
+#else
+ { "", "" },
+ { " ", "" },
+ { "hi", "hi" },
+ { " hi ", "hi" },
+ { "'hi'", "hi" },
+ { "hi ho", "hi ho" },
+ { "\"hi ho\" sucker", "'hi ho' sucker" },
+ { "\"hi\\\"ho\" sucker", "'hi\"ho' sucker" },
+ { "\"hi'ho\" sucker", "'hi'\\''ho' sucker" },
+ { "'hi ho' sucker", "'hi ho' sucker" },
+ { "\\\\", "'\\'" },
+ { "'\\'", "'\\'" },
+ { "hi 'null${here}too' ho", "hi 'null${here}too' ho" },
+ { "hi null${here}too ho", "hi {} ho" },
+ { "hi $(echo $dollar cent) ho", "hi {} ho" },
+ { "hi `echo $dollar \\`echo cent\\` | cat` ho", "hi {} ho" },
+ { "echo hello | more", "echo hello" },
+ { "echo hello| more", "echo hello" },
+#endif
+ };
+
+ for (unsigned i = 0; i < sizeof(vals)/sizeof(vals[0]); i++)
+ QTest::newRow(vals[i].in) << QString::fromLatin1(vals[i].in)
+ << QString::fromLatin1(vals[i].out);
+}
+
+void tst_QtcProcess::iterations()
+{
+ QFETCH(QString, in);
+ QFETCH(QString, out);
+
+ QString outstr;
+ for (QtcProcess::ArgIterator ait(&in); ait.next(); )
+ if (ait.isSimple())
+ QtcProcess::addArg(&outstr, ait.value());
+ else
+ QtcProcess::addArgs(&outstr, "{}");
+ QCOMPARE(outstr, out);
+}
+
+void tst_QtcProcess::iteratorEdits()
+{
+ QString in1 = "one two three", in2 = in1, in3 = in1, in4 = in1, in5 = in1;
+
+ QtcProcess::ArgIterator ait1(&in1);
+ 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"));
+
+ QtcProcess::ArgIterator ait2(&in2);
+ QVERIFY(ait2.next());
+ QVERIFY(ait2.next());
+ ait2.deleteArg();
+ QVERIFY(ait2.next());
+ ait2.appendArg("four");
+ QVERIFY(!ait2.next());
+ QCOMPARE(in2, QString::fromLatin1("one three four"));
+
+ QtcProcess::ArgIterator ait3(&in3);
+ 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"));
+
+ QtcProcess::ArgIterator ait4(&in4);
+ 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"));
+
+ QtcProcess::ArgIterator ait5(&in5);
+ QVERIFY(ait5.next());
+ QVERIFY(ait5.next());
+ QVERIFY(ait5.next());
+ QVERIFY(!ait5.next());
+ ait5.deleteArg();
+ QVERIFY(!ait5.next());
+ QCOMPARE(in5, QString::fromLatin1("one two"));
+}
+
+QTEST_MAIN(tst_QtcProcess)
+
+#include "tst_qtcprocess.moc"