File indexing completed on 2024-04-14 03:51:32

0001 /*
0002     This file is part of the KDE libraries
0003 
0004     SPDX-FileCopyrightText: 2003, 2007-2008 Oswald Buddenhagen <ossi@kde.org>
0005     SPDX-FileCopyrightText: 2005 Thomas Braxton <brax108@cox.net>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-only
0008 */
0009 
0010 #include <kshell.h>
0011 #include <kuser.h>
0012 
0013 #include <QTest>
0014 
0015 #include <QDir>
0016 #include <QObject>
0017 #include <QString>
0018 #include <QStringList>
0019 
0020 class KShellTest : public QObject
0021 {
0022     Q_OBJECT
0023 
0024 private Q_SLOTS:
0025     void tildeExpand();
0026     void tildeCollapse();
0027     void quoteArg();
0028     void joinArgs();
0029     void splitJoin();
0030     void quoteSplit();
0031     void quoteSplit_data();
0032     void abortOnMeta();
0033 };
0034 
0035 // The expansion of ~me isn't exactly QDir::homePath(), in case $HOME has a trailing slash, it's kept.
0036 static QString myHomePath()
0037 {
0038 #ifdef Q_OS_WIN
0039     return QDir::homePath();
0040 #else
0041     return QString::fromLocal8Bit(qgetenv("HOME"));
0042 #endif
0043 }
0044 
0045 void KShellTest::tildeExpand()
0046 {
0047     QString me(KUser().loginName());
0048     QCOMPARE(KShell::tildeExpand(QStringLiteral("~")), QDir::homePath());
0049     QCOMPARE(KShell::tildeExpand(QStringLiteral("~/dir")), QString(QDir::homePath() + QStringLiteral("/dir")));
0050     QCOMPARE(KShell::tildeExpand(QLatin1Char('~') + me), myHomePath());
0051     QCOMPARE(KShell::tildeExpand(QLatin1Char('~') + me + QStringLiteral("/dir")), QString(myHomePath() + QStringLiteral("/dir")));
0052 #ifdef Q_OS_WIN
0053     QCOMPARE(KShell::tildeExpand(QStringLiteral("^~") + me), QString(QLatin1Char('~') + me));
0054 #else
0055     QCOMPARE(KShell::tildeExpand(QStringLiteral("\\~") + me), QString(QStringLiteral("~") + me));
0056 #endif
0057 }
0058 
0059 void KShellTest::tildeCollapse()
0060 {
0061     QCOMPARE(KShell::tildeCollapse(QDir::homePath()), QStringLiteral("~"));
0062     QCOMPARE(KShell::tildeCollapse(QDir::homePath() + QStringLiteral("/Documents")), QStringLiteral("~/Documents"));
0063     QCOMPARE(KShell::tildeCollapse(QStringLiteral("/test/") + QDir::homePath()), QStringLiteral("/test/") + QDir::homePath());
0064 }
0065 
0066 void KShellTest::quoteArg()
0067 {
0068 #ifdef Q_OS_WIN
0069     QCOMPARE(KShell::quoteArg(QStringLiteral("a space")), QStringLiteral("\"a space\""));
0070     QCOMPARE(KShell::quoteArg(QStringLiteral("fds\\\"")), QStringLiteral("fds\\\\\\^\""));
0071     QCOMPARE(KShell::quoteArg(QStringLiteral("\\\\foo")), QStringLiteral("\\\\foo"));
0072     QCOMPARE(KShell::quoteArg(QStringLiteral("\"asdf\"")), QStringLiteral("\\^\"asdf\\^\""));
0073     QCOMPARE(KShell::quoteArg(QStringLiteral("with\\")), QStringLiteral("\"with\\\\\""));
0074     QCOMPARE(KShell::quoteArg(QStringLiteral("\\\\")), QStringLiteral("\"\\\\\\\\\""));
0075     QCOMPARE(KShell::quoteArg(QStringLiteral("\"a space\\\"")), QStringLiteral("\\^\"\"a space\"\\\\\\^\""));
0076     QCOMPARE(KShell::quoteArg(QStringLiteral("as df\\")), QStringLiteral("\"as df\\\\\""));
0077     QCOMPARE(KShell::quoteArg(QStringLiteral("foo bar\"\\\"bla")), QStringLiteral("\"foo bar\"\\^\"\\\\\\^\"\"bla\""));
0078     QCOMPARE(KShell::quoteArg(QStringLiteral("a % space")), QStringLiteral("\"a %PERCENT_SIGN% space\""));
0079 #else
0080     QCOMPARE(KShell::quoteArg(QStringLiteral("a space")), QStringLiteral("'a space'"));
0081 #endif
0082 }
0083 
0084 void KShellTest::joinArgs()
0085 {
0086     QStringList list;
0087     list << QStringLiteral("this") << QStringLiteral("is") << QStringLiteral("a") << QStringLiteral("test");
0088     QCOMPARE(KShell::joinArgs(list), QStringLiteral("this is a test"));
0089 }
0090 
0091 static QString sj(const QString &str, KShell::Options flags, KShell::Errors *ret)
0092 {
0093     return KShell::joinArgs(KShell::splitArgs(str, flags, ret));
0094 }
0095 
0096 void KShellTest::splitJoin()
0097 {
0098     KShell::Errors err = KShell::NoError;
0099 
0100 #ifdef Q_OS_WIN
0101     QCOMPARE(sj(QStringLiteral("\"(sulli)\" text"), KShell::NoOptions, &err), QStringLiteral("\"(sulli)\" text"));
0102     QVERIFY(err == KShell::NoError);
0103 
0104     QCOMPARE(sj(QStringLiteral(" ha\\ lo "), KShell::NoOptions, &err), QStringLiteral("\"ha\\\\\" lo"));
0105     QVERIFY(err == KShell::NoError);
0106 
0107     QCOMPARE(sj(QStringLiteral("say \" error"), KShell::NoOptions, &err), QString());
0108     QVERIFY(err == KShell::BadQuoting);
0109 
0110     QCOMPARE(sj(QStringLiteral("no \" error\""), KShell::NoOptions, &err), QStringLiteral("no \" error\""));
0111     QVERIFY(err == KShell::NoError);
0112 
0113     QCOMPARE(sj(QStringLiteral("say \" still error"), KShell::NoOptions, &err), QString());
0114     QVERIFY(err == KShell::BadQuoting);
0115 
0116     QCOMPARE(sj(QStringLiteral("BLA;asdf sdfess d"), KShell::NoOptions, &err), QStringLiteral("\"BLA;asdf\" sdfess d"));
0117     QVERIFY(err == KShell::NoError);
0118 
0119     QCOMPARE(sj(QStringLiteral("B\"L\"A&sdf FOO|bar sdf wer "), KShell::NoOptions, &err), QStringLiteral("\"BLA&sdf\" \"FOO|bar\" sdf wer"));
0120     QVERIFY(err == KShell::NoError);
0121 
0122     QCOMPARE(sj(QStringLiteral("\"\"\"just \"\" fine\"\"\""), KShell::NoOptions, &err), QStringLiteral("\\^\"\"just \"\\^\"\" fine\"\\^\""));
0123     QVERIFY(err == KShell::NoError);
0124 #else
0125     QCOMPARE(sj(QString::fromUtf8("\"~qU4rK\" 'text' 'jo'\"jo\" $'crap' $'\\\\\\'\\e\\x21' ha\\ lo \\a"), KShell::NoOptions, &err),
0126              QString::fromUtf8("'~qU4rK' text jojo crap '\\'\\''\x1b!' 'ha lo' a"));
0127     QVERIFY(err == KShell::NoError);
0128 
0129     QCOMPARE(sj(QStringLiteral("\"~qU4rK\" 'text'"), KShell::TildeExpand, &err), QStringLiteral("'~qU4rK' text"));
0130     QVERIFY(err == KShell::NoError);
0131 
0132     QCOMPARE(sj(QStringLiteral("~\"qU4rK\" 'text'"), KShell::TildeExpand, &err), QStringLiteral("'~qU4rK' text"));
0133     QVERIFY(err == KShell::NoError);
0134 
0135     QCOMPARE(sj(QStringLiteral("~/\"dir\" 'text'"), KShell::TildeExpand, &err), QString(QDir::homePath() + QStringLiteral("/dir text")));
0136     QVERIFY(err == KShell::NoError);
0137 
0138     QCOMPARE(sj(QStringLiteral("~ 'text' ~"), KShell::TildeExpand, &err), QString(QDir::homePath() + QStringLiteral(" text ") + QDir::homePath()));
0139     QVERIFY(err == KShell::NoError);
0140 
0141     QCOMPARE(sj(QStringLiteral("\\~ blah"), KShell::TildeExpand, &err), QStringLiteral("'~' blah"));
0142     QVERIFY(err == KShell::NoError);
0143 
0144     QCOMPARE(sj(QStringLiteral("~qU4rK ~") + KUser().loginName(), KShell::TildeExpand, &err), QString(QStringLiteral("'~qU4rK' ") + myHomePath()));
0145     QVERIFY(err == KShell::NoError);
0146 
0147     const QString unicodeSpaceFileName = QStringLiteral("test テスト.txt"); // #345140
0148     QCOMPARE(sj(unicodeSpaceFileName, KShell::AbortOnMeta | KShell::TildeExpand, &err), unicodeSpaceFileName);
0149     QVERIFY(err == KShell::NoError);
0150 #endif
0151 }
0152 
0153 void KShellTest::quoteSplit_data()
0154 {
0155     QTest::addColumn<QString>("string");
0156 
0157     QTest::newRow("no space") << QStringLiteral("hiho");
0158     QTest::newRow("regular space") << QStringLiteral("hi there");
0159     QTest::newRow("special space") << QString::fromUtf8("如何定期清潔典型的電風扇 講義.pdf");
0160 }
0161 
0162 void KShellTest::quoteSplit()
0163 {
0164     QFETCH(QString, string);
0165 
0166     // Splitting a quote arg should always just return one argument
0167     const QStringList args = KShell::splitArgs(KShell::quoteArg(string));
0168     QCOMPARE(args.count(), 1);
0169 }
0170 
0171 void KShellTest::abortOnMeta()
0172 {
0173     KShell::Errors err1 = KShell::NoError;
0174     KShell::Errors err2 = KShell::NoError;
0175 
0176     QCOMPARE(sj(QStringLiteral("text"), KShell::AbortOnMeta, &err1), QStringLiteral("text"));
0177     QVERIFY(err1 == KShell::NoError);
0178 
0179 #ifdef Q_OS_WIN
0180     QVERIFY(KShell::splitArgs(QStringLiteral("BLA & asdf sdfess d"), KShell::AbortOnMeta, &err1).isEmpty());
0181     QVERIFY(err1 == KShell::FoundMeta);
0182 
0183     QVERIFY(KShell::splitArgs(QStringLiteral("foo %PATH% bar"), KShell::AbortOnMeta, &err1).isEmpty());
0184     QVERIFY(err1 == KShell::FoundMeta);
0185     QCOMPARE(sj(QStringLiteral("foo %PERCENT_SIGN% bar"), KShell::AbortOnMeta, &err1), QStringLiteral("foo %PERCENT_SIGN% bar"));
0186     QVERIFY(err1 == KShell::NoError);
0187 
0188     QCOMPARE(sj(QStringLiteral("@foo ^& bar"), KShell::AbortOnMeta, &err1), QStringLiteral("foo \"&\" bar"));
0189     QVERIFY(err1 == KShell::NoError);
0190 
0191     QCOMPARE(sj(QStringLiteral("\"BLA|asdf\" sdfess d"), KShell::AbortOnMeta, &err1), QStringLiteral("\"BLA|asdf\" sdfess d"));
0192     QVERIFY(err1 == KShell::NoError);
0193 
0194     QCOMPARE(sj(QStringLiteral("B\"L\"A\"|\"sdf \"FOO | bar\" sdf wer"), KShell::AbortOnMeta, &err1), QStringLiteral("\"BLA|sdf\" \"FOO | bar\" sdf wer"));
0195     QVERIFY(err1 == KShell::NoError);
0196 
0197     QCOMPARE(sj(QStringLiteral("b-q me \\\\^|\\\\\\^\""), KShell::AbortOnMeta, &err1), QStringLiteral("b-q me \"\\\\|\"\\\\\\^\""));
0198     QVERIFY(err1 == KShell::NoError);
0199 #else
0200     QCOMPARE(sj(QStringLiteral("say \" error"), KShell::NoOptions, &err1), QString());
0201     QVERIFY(err1 != KShell::NoError);
0202 
0203     QCOMPARE(sj(QStringLiteral("say \" still error"), KShell::AbortOnMeta, &err1), QString());
0204     QVERIFY(err1 != KShell::NoError);
0205 
0206     QVERIFY(sj(QStringLiteral("say `echo no error`"), KShell::NoOptions, &err1) != sj(QStringLiteral("say `echo no error`"), KShell::AbortOnMeta, &err2));
0207     QVERIFY(err1 != err2);
0208 
0209     QVERIFY(sj(QStringLiteral("BLA=say echo meta"), KShell::NoOptions, &err1) != sj(QStringLiteral("BLA=say echo meta"), KShell::AbortOnMeta, &err2));
0210     QVERIFY(err1 != err2);
0211 
0212     QVERIFY(sj(QStringLiteral("B\"L\"A=say FOO=bar echo meta"), KShell::NoOptions, &err1)
0213             == sj(QStringLiteral("B\"L\"A=say FOO=bar echo meta"), KShell::AbortOnMeta, &err2));
0214 #endif
0215 }
0216 
0217 QTEST_MAIN(KShellTest)
0218 
0219 #include "kshelltest.moc"