forked from qt-creator/qt-creator
Utils: Remove AbstractMacroExpander
It was only used by its own tests. Instead move the functionality into MacroExpander(Private). The existing unittests are moved into tst_expander. Change-Id: Ia54f659efa7976b17f47a0084900f98acc834939 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -766,7 +766,7 @@ static int quoteArgInternalWin(QString &ret, int bslashes)
|
||||
* \return false if the string could not be parsed and therefore no safe
|
||||
* substitution was possible
|
||||
*/
|
||||
bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType osType)
|
||||
bool ProcessArgs::expandMacros(QString *cmd, const FindMacro &findMacro, OsType osType)
|
||||
{
|
||||
QString str = *cmd;
|
||||
if (str.isEmpty())
|
||||
@@ -775,7 +775,7 @@ bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType o
|
||||
QString rsts;
|
||||
int varLen;
|
||||
int varPos = 0;
|
||||
if (!(varLen = mx->findMacro(str, &varPos, &rsts)))
|
||||
if (!(varLen = findMacro(str, &varPos, &rsts)))
|
||||
return true;
|
||||
|
||||
int pos = 0;
|
||||
@@ -839,7 +839,7 @@ bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType o
|
||||
str.replace(pos, varLen, rsts);
|
||||
pos += rsts.length();
|
||||
varPos = pos;
|
||||
if (!(varLen = mx->findMacro(str, &varPos, &rsts))) {
|
||||
if (!(varLen = findMacro(str, &varPos, &rsts))) {
|
||||
// Don't leave immediately, as we may be in CrtNeedWord state which could
|
||||
// be still resolved, or we may have inserted trailing backslashes.
|
||||
varPos = INT_MAX;
|
||||
@@ -954,7 +954,7 @@ bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType o
|
||||
str.replace(pos, varLen, rsts);
|
||||
pos += rsts.length();
|
||||
varPos = pos;
|
||||
if (!(varLen = mx->findMacro(str, &varPos, &rsts)))
|
||||
if (!(varLen = findMacro(str, &varPos, &rsts)))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
@@ -59,9 +59,12 @@ public:
|
||||
static QStringList splitArgs(const QString &cmd, OsType osType,
|
||||
bool abortOnMeta = false, SplitError *err = nullptr,
|
||||
const Environment *env = nullptr, const QString *pwd = nullptr);
|
||||
|
||||
using FindMacro = std::function<int(const QString &str, int *pos, QString *ret)>;
|
||||
|
||||
//! Safely replace the expandos in a shell command
|
||||
static bool expandMacros(QString *cmd, AbstractMacroExpander *mx,
|
||||
OsType osType = HostOsInfo::hostOs());
|
||||
static bool expandMacros(
|
||||
QString *cmd, const FindMacro &findMacro, OsType osType = HostOsInfo::hostOs());
|
||||
|
||||
/*! Iterate over arguments from a command line.
|
||||
* Assumes that the name of the actual command is *not* part of the line.
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <QFileInfo>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMap>
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace Utils {
|
||||
namespace Internal {
|
||||
@@ -27,12 +28,112 @@ const char kNativePathPostfix[] = ":NativePath";
|
||||
const char kFileNamePostfix[] = ":FileName";
|
||||
const char kFileBaseNamePostfix[] = ":FileBaseName";
|
||||
|
||||
class MacroExpanderPrivate : public AbstractMacroExpander
|
||||
class MacroExpanderPrivate
|
||||
{
|
||||
public:
|
||||
MacroExpanderPrivate() = default;
|
||||
|
||||
bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander *> &seen) override
|
||||
static bool validateVarName(const QString &varName) { return !varName.startsWith("JS:"); }
|
||||
|
||||
bool expandNestedMacros(const QString &str, int *pos, QString *ret)
|
||||
{
|
||||
QString varName;
|
||||
QString pattern, replace;
|
||||
QString defaultValue;
|
||||
QString *currArg = &varName;
|
||||
QChar prev;
|
||||
QChar c;
|
||||
QChar replacementChar;
|
||||
bool replaceAll = false;
|
||||
|
||||
int i = *pos;
|
||||
int strLen = str.length();
|
||||
varName.reserve(strLen - i);
|
||||
for (; i < strLen; prev = c) {
|
||||
c = str.at(i++);
|
||||
if (c == '\\' && i < strLen) {
|
||||
c = str.at(i++);
|
||||
// For the replacement, do not skip the escape sequence when followed by a digit.
|
||||
// This is needed for enabling convenient capture group replacement,
|
||||
// like %{var/(.)(.)/\2\1}, without escaping the placeholders.
|
||||
if (currArg == &replace && c.isDigit())
|
||||
*currArg += '\\';
|
||||
*currArg += c;
|
||||
} else if (c == '}') {
|
||||
if (varName.isEmpty()) { // replace "%{}" with "%"
|
||||
*ret = QString('%');
|
||||
*pos = i;
|
||||
return true;
|
||||
}
|
||||
QSet<MacroExpanderPrivate *> seen;
|
||||
if (resolveMacro(varName, ret, seen)) {
|
||||
*pos = i;
|
||||
if (!pattern.isEmpty() && currArg == &replace) {
|
||||
const QRegularExpression regexp(pattern);
|
||||
if (regexp.isValid()) {
|
||||
if (replaceAll) {
|
||||
ret->replace(regexp, replace);
|
||||
} else {
|
||||
// There isn't an API for replacing once...
|
||||
const QRegularExpressionMatch match = regexp.match(*ret);
|
||||
if (match.hasMatch()) {
|
||||
*ret = ret->left(match.capturedStart(0))
|
||||
+ match.captured(0).replace(regexp, replace)
|
||||
+ ret->mid(match.capturedEnd(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!defaultValue.isEmpty()) {
|
||||
*pos = i;
|
||||
*ret = defaultValue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (c == '{' && prev == '%') {
|
||||
if (!expandNestedMacros(str, &i, ret))
|
||||
return false;
|
||||
varName.chop(1);
|
||||
varName += *ret;
|
||||
} else if (currArg == &varName && c == '-' && prev == ':' && validateVarName(varName)) {
|
||||
varName.chop(1);
|
||||
currArg = &defaultValue;
|
||||
} else if (currArg == &varName && (c == '/' || c == '#') && validateVarName(varName)) {
|
||||
replacementChar = c;
|
||||
currArg = &pattern;
|
||||
if (i < strLen && str.at(i) == replacementChar) {
|
||||
++i;
|
||||
replaceAll = true;
|
||||
}
|
||||
} else if (currArg == &pattern && c == replacementChar) {
|
||||
currArg = &replace;
|
||||
} else {
|
||||
*currArg += c;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int findMacro(const QString &str, int *pos, QString *ret)
|
||||
{
|
||||
forever {
|
||||
int openPos = str.indexOf("%{", *pos);
|
||||
if (openPos < 0)
|
||||
return 0;
|
||||
int varPos = openPos + 2;
|
||||
if (expandNestedMacros(str, &varPos, ret)) {
|
||||
*pos = openPos;
|
||||
return varPos - openPos;
|
||||
}
|
||||
// An actual expansion may be nested into a "false" one,
|
||||
// so we continue right after the last %{.
|
||||
*pos = openPos + 2;
|
||||
}
|
||||
}
|
||||
|
||||
bool resolveMacro(const QString &name, QString *ret, QSet<MacroExpanderPrivate *> &seen)
|
||||
{
|
||||
// Prevent loops:
|
||||
const int count = seen.count();
|
||||
@@ -229,7 +330,7 @@ MacroExpander::~MacroExpander()
|
||||
*/
|
||||
bool MacroExpander::resolveMacro(const QString &name, QString *ret) const
|
||||
{
|
||||
QSet<AbstractMacroExpander*> seen;
|
||||
QSet<MacroExpanderPrivate *> seen;
|
||||
return d->resolveMacro(name, ret, seen);
|
||||
}
|
||||
|
||||
@@ -242,6 +343,16 @@ QString MacroExpander::value(const QByteArray &variable, bool *found) const
|
||||
return d->value(variable, found);
|
||||
}
|
||||
|
||||
static void expandMacros(QString *str, MacroExpanderPrivate *mx)
|
||||
{
|
||||
QString rsts;
|
||||
|
||||
for (int pos = 0; int len = mx->findMacro(*str, &pos, &rsts);) {
|
||||
str->replace(pos, len, rsts);
|
||||
pos += rsts.length();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns \a stringWithVariables with all variables replaced by their values.
|
||||
* See the MacroExpander overview documentation for other ways to expand variables.
|
||||
@@ -261,7 +372,7 @@ QString MacroExpander::expand(const QString &stringWithVariables) const
|
||||
++d->m_lockDepth;
|
||||
|
||||
QString res = stringWithVariables;
|
||||
Utils::expandMacros(&res, d);
|
||||
expandMacros(&res, d);
|
||||
|
||||
--d->m_lockDepth;
|
||||
|
||||
@@ -302,10 +413,14 @@ QVariant MacroExpander::expandVariant(const QVariant &v) const
|
||||
return v;
|
||||
}
|
||||
|
||||
QString MacroExpander::expandProcessArgs(const QString &argsWithVariables) const
|
||||
QString MacroExpander::expandProcessArgs(const QString &argsWithVariables, Utils::OsType osType) const
|
||||
{
|
||||
QString result = argsWithVariables;
|
||||
const bool ok = ProcessArgs::expandMacros(&result, d);
|
||||
const bool ok = ProcessArgs::expandMacros(
|
||||
&result,
|
||||
[this](const QString &str, int *pos, QString *ret) { return d->findMacro(str, pos, ret); },
|
||||
osType);
|
||||
|
||||
QTC_ASSERT(ok, qCDebug(expanderLog) << "Expanding failed: " << argsWithVariables);
|
||||
return result;
|
||||
}
|
||||
|
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "utils_global.h"
|
||||
|
||||
#include "hostosinfo.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
#include <functional>
|
||||
@@ -35,7 +37,8 @@ public:
|
||||
QByteArray expand(const QByteArray &stringWithVariables) const;
|
||||
QVariant expandVariant(const QVariant &v) const;
|
||||
|
||||
QString expandProcessArgs(const QString &argsWithVariables) const;
|
||||
QString expandProcessArgs(
|
||||
const QString &argsWithVariables, Utils::OsType osType = Utils::HostOsInfo::hostOs()) const;
|
||||
|
||||
using PrefixFunction = std::function<QString(QString)>;
|
||||
using ResolverFunction = std::function<bool(QString, QString *)>;
|
||||
|
@@ -78,126 +78,6 @@ QTCREATOR_UTILS_EXPORT QString commonPrefix(const QStringList &strings)
|
||||
return strings.at(0).left(commonLength);
|
||||
}
|
||||
|
||||
static bool validateVarName(const QString &varName)
|
||||
{
|
||||
return !varName.startsWith("JS:");
|
||||
}
|
||||
|
||||
bool AbstractMacroExpander::expandNestedMacros(const QString &str, int *pos, QString *ret)
|
||||
{
|
||||
QString varName;
|
||||
QString pattern, replace;
|
||||
QString defaultValue;
|
||||
QString *currArg = &varName;
|
||||
QChar prev;
|
||||
QChar c;
|
||||
QChar replacementChar;
|
||||
bool replaceAll = false;
|
||||
|
||||
int i = *pos;
|
||||
int strLen = str.length();
|
||||
varName.reserve(strLen - i);
|
||||
for (; i < strLen; prev = c) {
|
||||
c = str.at(i++);
|
||||
if (c == '\\' && i < strLen) {
|
||||
c = str.at(i++);
|
||||
// For the replacement, do not skip the escape sequence when followed by a digit.
|
||||
// This is needed for enabling convenient capture group replacement,
|
||||
// like %{var/(.)(.)/\2\1}, without escaping the placeholders.
|
||||
if (currArg == &replace && c.isDigit())
|
||||
*currArg += '\\';
|
||||
*currArg += c;
|
||||
} else if (c == '}') {
|
||||
if (varName.isEmpty()) { // replace "%{}" with "%"
|
||||
*ret = QString('%');
|
||||
*pos = i;
|
||||
return true;
|
||||
}
|
||||
QSet<AbstractMacroExpander*> seen;
|
||||
if (resolveMacro(varName, ret, seen)) {
|
||||
*pos = i;
|
||||
if (!pattern.isEmpty() && currArg == &replace) {
|
||||
const QRegularExpression regexp(pattern);
|
||||
if (regexp.isValid()) {
|
||||
if (replaceAll) {
|
||||
ret->replace(regexp, replace);
|
||||
} else {
|
||||
// There isn't an API for replacing once...
|
||||
const QRegularExpressionMatch match = regexp.match(*ret);
|
||||
if (match.hasMatch()) {
|
||||
*ret = ret->left(match.capturedStart(0))
|
||||
+ match.captured(0).replace(regexp, replace)
|
||||
+ ret->mid(match.capturedEnd(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!defaultValue.isEmpty()) {
|
||||
*pos = i;
|
||||
*ret = defaultValue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (c == '{' && prev == '%') {
|
||||
if (!expandNestedMacros(str, &i, ret))
|
||||
return false;
|
||||
varName.chop(1);
|
||||
varName += *ret;
|
||||
} else if (currArg == &varName && c == '-' && prev == ':' && validateVarName(varName)) {
|
||||
varName.chop(1);
|
||||
currArg = &defaultValue;
|
||||
} else if (currArg == &varName && (c == '/' || c == '#') && validateVarName(varName)) {
|
||||
replacementChar = c;
|
||||
currArg = &pattern;
|
||||
if (i < strLen && str.at(i) == replacementChar) {
|
||||
++i;
|
||||
replaceAll = true;
|
||||
}
|
||||
} else if (currArg == &pattern && c == replacementChar) {
|
||||
currArg = &replace;
|
||||
} else {
|
||||
*currArg += c;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AbstractMacroExpander::findMacro(const QString &str, int *pos, QString *ret)
|
||||
{
|
||||
forever {
|
||||
int openPos = str.indexOf("%{", *pos);
|
||||
if (openPos < 0)
|
||||
return 0;
|
||||
int varPos = openPos + 2;
|
||||
if (expandNestedMacros(str, &varPos, ret)) {
|
||||
*pos = openPos;
|
||||
return varPos - openPos;
|
||||
}
|
||||
// An actual expansion may be nested into a "false" one,
|
||||
// so we continue right after the last %{.
|
||||
*pos = openPos + 2;
|
||||
}
|
||||
}
|
||||
|
||||
QTCREATOR_UTILS_EXPORT void expandMacros(QString *str, AbstractMacroExpander *mx)
|
||||
{
|
||||
QString rsts;
|
||||
|
||||
for (int pos = 0; int len = mx->findMacro(*str, &pos, &rsts); ) {
|
||||
str->replace(pos, len, rsts);
|
||||
pos += rsts.length();
|
||||
}
|
||||
}
|
||||
|
||||
QTCREATOR_UTILS_EXPORT QString expandMacros(const QString &str, AbstractMacroExpander *mx)
|
||||
{
|
||||
QString ret = str;
|
||||
expandMacros(&ret, mx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
QTCREATOR_UTILS_EXPORT QString stripAccelerator(const QString &text)
|
||||
{
|
||||
QString res = text;
|
||||
|
@@ -41,29 +41,6 @@ QTCREATOR_UTILS_EXPORT bool readMultiLineString(const QJsonValue &value, QString
|
||||
// Compare case insensitive and use case sensitive comparison in case of that being equal.
|
||||
QTCREATOR_UTILS_EXPORT int caseFriendlyCompare(const QString &a, const QString &b);
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT AbstractMacroExpander
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractMacroExpander() {}
|
||||
// Not const, as it may change the state of the expander.
|
||||
//! Find an expando to replace and provide a replacement string.
|
||||
//! \param str The string to scan
|
||||
//! \param pos Position to start scan on input, found position on output
|
||||
//! \param ret Replacement string on output
|
||||
//! \return Length of string part to replace, zero if no (further) matches found
|
||||
virtual int findMacro(const QString &str, int *pos, QString *ret);
|
||||
//! Provide a replacement string for an expando
|
||||
//! \param name The name of the expando
|
||||
//! \param ret Replacement string on output
|
||||
//! \return True if the expando was found
|
||||
virtual bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander *> &seen) = 0;
|
||||
private:
|
||||
bool expandNestedMacros(const QString &str, int *pos, QString *ret);
|
||||
};
|
||||
|
||||
QTCREATOR_UTILS_EXPORT void expandMacros(QString *str, AbstractMacroExpander *mx);
|
||||
QTCREATOR_UTILS_EXPORT QString expandMacros(const QString &str, AbstractMacroExpander *mx);
|
||||
|
||||
QTCREATOR_UTILS_EXPORT int parseUsedPortFromNetstatOutput(const QByteArray &line);
|
||||
|
||||
QTCREATOR_UTILS_EXPORT QString appendHelper(const QString &base, int n);
|
||||
|
@@ -173,6 +173,7 @@ private slots:
|
||||
{
|
||||
QTest::addColumn<QString>("input");
|
||||
QTest::addColumn<QString>("expected");
|
||||
QTest::addColumn<OsType>("os");
|
||||
QTest::addColumn<std::function<void(MacroExpander &)>>("setup");
|
||||
|
||||
std::function<void(MacroExpander &)> empty;
|
||||
@@ -184,57 +185,63 @@ private slots:
|
||||
expander.registerVariable("WithSpace", "", [] { return "This has spaces"; });
|
||||
};
|
||||
|
||||
QTest::newRow("empty") << QString() << QString() << empty;
|
||||
QTest::newRow("no expansion") << QString("foo") << QString("foo") << empty;
|
||||
QTest::newRow("empty") << QString() << QString() << Utils::OsTypeLinux << empty;
|
||||
QTest::newRow("no expansion")
|
||||
<< QString("foo") << QString("foo") << Utils::OsTypeLinux << empty;
|
||||
|
||||
QTest::newRow("simple-expansion")
|
||||
<< QString("cat %{file}") << QString("cat foo.txt") << file;
|
||||
<< QString("cat %{file}") << QString("cat foo.txt") << Utils::OsTypeLinux << file;
|
||||
|
||||
QTest::newRow("with-ticks")
|
||||
<< QString("echo -n 'foo %{file}'") << QString("echo -n 'foo foo.txt'") << file;
|
||||
<< QString("echo -n 'foo %{file}'") << QString("echo -n 'foo foo.txt'")
|
||||
<< Utils::OsTypeLinux << file;
|
||||
|
||||
QTest::newRow("with-ticks-env") << QString("file=%{file} echo -n 'foo \"$file\"'")
|
||||
<< QString("file=foo.txt echo -n 'foo \"$file\"'") << file;
|
||||
QTest::newRow("with-ticks-env")
|
||||
<< QString("file=%{file} echo -n 'foo \"$file\"'")
|
||||
<< QString("file=foo.txt echo -n 'foo \"$file\"'") << Utils::OsTypeLinux << file;
|
||||
|
||||
if (Utils::HostOsInfo::isWindowsHost()) {
|
||||
QTest::newRow("with-spaces")
|
||||
<< QString("echo %{WithSpace}") << QString("echo \"This has spaces\"") << withspace;
|
||||
QTest::newRow("with-spaces")
|
||||
<< QString("echo %{WithSpace}") << QString("echo 'This has spaces'")
|
||||
<< Utils::OsTypeLinux << withspace;
|
||||
|
||||
QTest::newRow("with-spaces-manual")
|
||||
<< QString("echo \"Some: %{WithSpace}\"")
|
||||
<< QString("echo \"Some: This has spaces\"") << withspace;
|
||||
QTest::newRow("with-spaces-pre-quoted")
|
||||
<< QString("echo 'Some: %{WithSpace}'") << QString("echo 'Some: This has spaces'")
|
||||
<< Utils::OsTypeLinux << withspace;
|
||||
|
||||
QTest::newRow("with-spaces-nested")
|
||||
<< QString("cmd /k \"echo %{WithSpace}\"")
|
||||
<< QString("cmd /k \"echo This has spaces\"") << withspace;
|
||||
} else {
|
||||
QTest::newRow("with-spaces")
|
||||
<< QString("echo %{WithSpace}") << QString("echo 'This has spaces'") << withspace;
|
||||
QTest::newRow("with-spaces-nested")
|
||||
<< QString("sh -c 'echo %{WithSpace}'") << QString("sh -c 'echo This has spaces'")
|
||||
<< Utils::OsTypeLinux << withspace;
|
||||
|
||||
QTest::newRow("with-spaces-pre-quoted")
|
||||
<< QString("echo 'Some: %{WithSpace}'") << QString("echo 'Some: This has spaces'")
|
||||
<< withspace;
|
||||
// Due to security concerns, backslash-escaping an expando is treated as a quoting error
|
||||
QTest::newRow("backslash-escaping")
|
||||
<< QString("echo \\%{file}") << QString("echo \\%{file}") << Utils::OsTypeLinux << file;
|
||||
|
||||
QTest::newRow("with-spaces-nested")
|
||||
<< QString("sh -c 'echo %{WithSpace}'") << QString("sh -c 'echo This has spaces'")
|
||||
<< withspace;
|
||||
QTest::newRow("expando-within-shell-substitution")
|
||||
<< QString("${VAR:-%{file}}") << QString("${VAR:-foo.txt}") << Utils::OsTypeLinux
|
||||
<< file;
|
||||
QTest::newRow("expando-within-shell-substitution-with-space")
|
||||
<< QString("echo \"Some: ${VAR:-%{WithSpace}}\"")
|
||||
<< QString("echo \"Some: ${VAR:-This has spaces}\"") << Utils::OsTypeLinux << withspace;
|
||||
|
||||
// Due to security concerns, backslash-escaping an expando is treated as a quoting error
|
||||
QTest::newRow("backslash-escaping")
|
||||
<< QString("echo \\%{file}") << QString("echo \\%{file}") << file;
|
||||
// Windows tests
|
||||
QTest::newRow("with-spaces")
|
||||
<< QString("echo %{WithSpace}") << QString("echo \"This has spaces\"")
|
||||
<< Utils::OsTypeWindows << withspace;
|
||||
|
||||
QTest::newRow("expando-within-shell-substitution")
|
||||
<< QString("${VAR:-%{file}}") << QString("${VAR:-foo.txt}") << file;
|
||||
QTest::newRow("expando-within-shell-substitution-with-space")
|
||||
<< QString("echo \"Some: ${VAR:-%{WithSpace}}\"")
|
||||
<< QString("echo \"Some: ${VAR:-This has spaces}\"") << withspace;
|
||||
}
|
||||
QTest::newRow("with-spaces-manual")
|
||||
<< QString("echo \"Some: %{WithSpace}\"") << QString("echo \"Some: This has spaces\"")
|
||||
<< Utils::OsTypeWindows << withspace;
|
||||
|
||||
QTest::newRow("with-spaces-nested")
|
||||
<< QString("cmd /k \"echo %{WithSpace}\"") << QString("cmd /k \"echo This has spaces\"")
|
||||
<< Utils::OsTypeWindows << withspace;
|
||||
}
|
||||
|
||||
void expandCommandArgs()
|
||||
{
|
||||
QFETCH(QString, input);
|
||||
QFETCH(QString, expected);
|
||||
QFETCH(OsType, os);
|
||||
QFETCH(std::function<void(MacroExpander &)>, setup);
|
||||
|
||||
MacroExpander expander;
|
||||
@@ -242,7 +249,354 @@ private slots:
|
||||
if (setup)
|
||||
setup(expander);
|
||||
|
||||
QCOMPARE(expander.expandProcessArgs(input), expected);
|
||||
QCOMPARE(expander.expandProcessArgs(input, os), expected);
|
||||
}
|
||||
|
||||
void expandProcessArgs_data()
|
||||
{
|
||||
QTest::addColumn<QString>("in");
|
||||
QTest::addColumn<QString>("out");
|
||||
QTest::addColumn<OsType>("os");
|
||||
QChar sp(QLatin1Char(' '));
|
||||
|
||||
struct Val
|
||||
{
|
||||
const char *in;
|
||||
const char *out;
|
||||
OsType os;
|
||||
};
|
||||
|
||||
const std::array vals
|
||||
= {Val{"plain", 0, OsTypeWindows},
|
||||
Val{"%{a}", "hi", OsTypeWindows},
|
||||
Val{"%{aa}", "\"hi ho\"", OsTypeWindows},
|
||||
Val{"%{b}", "h\\i", OsTypeWindows},
|
||||
Val{"%{c}", "\\hi", OsTypeWindows},
|
||||
Val{"%{d}", "hi\\", OsTypeWindows},
|
||||
Val{"%{ba}", "\"h\\i ho\"", OsTypeWindows},
|
||||
Val{"%{ca}", "\"\\hi ho\"", OsTypeWindows},
|
||||
Val{"%{da}", "\"hi ho\\\\\"", OsTypeWindows}, // or "\"hi ho\"\\"
|
||||
Val{"%{e}", "\"h\"\\^\"\"i\"", OsTypeWindows},
|
||||
Val{"%{f}", "\"\"\\^\"\"hi\"", OsTypeWindows},
|
||||
Val{"%{g}", "\"hi\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"%{h}", "\"h\\\\\"\\^\"\"i\"", OsTypeWindows},
|
||||
Val{"%{i}", "\"\\\\\"\\^\"\"hi\"", OsTypeWindows},
|
||||
Val{"%{j}", "\"hi\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"%{k}", "\"&special;\"", OsTypeWindows},
|
||||
Val{"%{x}", "\\", OsTypeWindows},
|
||||
Val{"%{y}", "\"\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"%{z}", "\"\"", OsTypeWindows},
|
||||
Val{"^%{z}%{z}", "^%{z}%{z}", OsTypeWindows}, // stupid user check
|
||||
|
||||
Val{"quoted", 0, OsTypeWindows},
|
||||
Val{"\"%{a}\"", "\"hi\"", OsTypeWindows},
|
||||
Val{"\"%{aa}\"", "\"hi ho\"", OsTypeWindows},
|
||||
Val{"\"%{b}\"", "\"h\\i\"", OsTypeWindows},
|
||||
Val{"\"%{c}\"", "\"\\hi\"", OsTypeWindows},
|
||||
Val{"\"%{d}\"", "\"hi\\\\\"", OsTypeWindows},
|
||||
Val{"\"%{ba}\"", "\"h\\i ho\"", OsTypeWindows},
|
||||
Val{"\"%{ca}\"", "\"\\hi ho\"", OsTypeWindows},
|
||||
Val{"\"%{da}\"", "\"hi ho\\\\\"", OsTypeWindows},
|
||||
Val{"\"%{e}\"", "\"h\"\\^\"\"i\"", OsTypeWindows},
|
||||
Val{"\"%{f}\"", "\"\"\\^\"\"hi\"", OsTypeWindows},
|
||||
Val{"\"%{g}\"", "\"hi\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{h}\"", "\"h\\\\\"\\^\"\"i\"", OsTypeWindows},
|
||||
Val{"\"%{i}\"", "\"\\\\\"\\^\"\"hi\"", OsTypeWindows},
|
||||
Val{"\"%{j}\"", "\"hi\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{k}\"", "\"&special;\"", OsTypeWindows},
|
||||
Val{"\"%{x}\"", "\"\\\\\"", OsTypeWindows},
|
||||
Val{"\"%{y}\"", "\"\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{z}\"", "\"\"", OsTypeWindows},
|
||||
|
||||
Val{"leading bs", 0, OsTypeWindows},
|
||||
Val{"\\%{a}", "\\hi", OsTypeWindows},
|
||||
Val{"\\%{aa}", "\\\\\"hi ho\"", OsTypeWindows},
|
||||
Val{"\\%{b}", "\\h\\i", OsTypeWindows},
|
||||
Val{"\\%{c}", "\\\\hi", OsTypeWindows},
|
||||
Val{"\\%{d}", "\\hi\\", OsTypeWindows},
|
||||
Val{"\\%{ba}", "\\\\\"h\\i ho\"", OsTypeWindows},
|
||||
Val{"\\%{ca}", "\\\\\"\\hi ho\"", OsTypeWindows},
|
||||
Val{"\\%{da}", "\\\\\"hi ho\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{e}", "\\\\\"h\"\\^\"\"i\"", OsTypeWindows},
|
||||
Val{"\\%{f}", "\\\\\"\"\\^\"\"hi\"", OsTypeWindows},
|
||||
Val{"\\%{g}", "\\\\\"hi\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\\%{h}", "\\\\\"h\\\\\"\\^\"\"i\"", OsTypeWindows},
|
||||
Val{"\\%{i}", "\\\\\"\\\\\"\\^\"\"hi\"", OsTypeWindows},
|
||||
Val{"\\%{j}", "\\\\\"hi\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\\%{x}", "\\\\", OsTypeWindows},
|
||||
Val{"\\%{y}", "\\\\\"\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\\%{z}", "\\", OsTypeWindows},
|
||||
|
||||
Val{"trailing bs", 0, OsTypeWindows},
|
||||
Val{"%{a}\\", "hi\\", OsTypeWindows},
|
||||
Val{"%{aa}\\", "\"hi ho\"\\", OsTypeWindows},
|
||||
Val{"%{b}\\", "h\\i\\", OsTypeWindows},
|
||||
Val{"%{c}\\", "\\hi\\", OsTypeWindows},
|
||||
Val{"%{d}\\", "hi\\\\", OsTypeWindows},
|
||||
Val{"%{ba}\\", "\"h\\i ho\"\\", OsTypeWindows},
|
||||
Val{"%{ca}\\", "\"\\hi ho\"\\", OsTypeWindows},
|
||||
Val{"%{da}\\", "\"hi ho\\\\\"\\", OsTypeWindows},
|
||||
Val{"%{e}\\", "\"h\"\\^\"\"i\"\\", OsTypeWindows},
|
||||
Val{"%{f}\\", "\"\"\\^\"\"hi\"\\", OsTypeWindows},
|
||||
Val{"%{g}\\", "\"hi\"\\^\"\"\"\\", OsTypeWindows},
|
||||
Val{"%{h}\\", "\"h\\\\\"\\^\"\"i\"\\", OsTypeWindows},
|
||||
Val{"%{i}\\", "\"\\\\\"\\^\"\"hi\"\\", OsTypeWindows},
|
||||
Val{"%{j}\\", "\"hi\\\\\"\\^\"\"\"\\", OsTypeWindows},
|
||||
Val{"%{x}\\", "\\\\", OsTypeWindows},
|
||||
Val{"%{y}\\", "\"\"\\^\"\"\"\\", OsTypeWindows},
|
||||
Val{"%{z}\\", "\\", OsTypeWindows},
|
||||
|
||||
Val{"bs-enclosed", 0, OsTypeWindows},
|
||||
Val{"\\%{a}\\", "\\hi\\", OsTypeWindows},
|
||||
Val{"\\%{aa}\\", "\\\\\"hi ho\"\\", OsTypeWindows},
|
||||
Val{"\\%{b}\\", "\\h\\i\\", OsTypeWindows},
|
||||
Val{"\\%{c}\\", "\\\\hi\\", OsTypeWindows},
|
||||
Val{"\\%{d}\\", "\\hi\\\\", OsTypeWindows},
|
||||
Val{"\\%{ba}\\", "\\\\\"h\\i ho\"\\", OsTypeWindows},
|
||||
Val{"\\%{ca}\\", "\\\\\"\\hi ho\"\\", OsTypeWindows},
|
||||
Val{"\\%{da}\\", "\\\\\"hi ho\\\\\"\\", OsTypeWindows},
|
||||
Val{"\\%{e}\\", "\\\\\"h\"\\^\"\"i\"\\", OsTypeWindows},
|
||||
Val{"\\%{f}\\", "\\\\\"\"\\^\"\"hi\"\\", OsTypeWindows},
|
||||
Val{"\\%{g}\\", "\\\\\"hi\"\\^\"\"\"\\", OsTypeWindows},
|
||||
Val{"\\%{h}\\", "\\\\\"h\\\\\"\\^\"\"i\"\\", OsTypeWindows},
|
||||
Val{"\\%{i}\\", "\\\\\"\\\\\"\\^\"\"hi\"\\", OsTypeWindows},
|
||||
Val{"\\%{j}\\", "\\\\\"hi\\\\\"\\^\"\"\"\\", OsTypeWindows},
|
||||
Val{"\\%{x}\\", "\\\\\\", OsTypeWindows},
|
||||
Val{"\\%{y}\\", "\\\\\"\"\\^\"\"\"\\", OsTypeWindows},
|
||||
Val{"\\%{z}\\", "\\\\", OsTypeWindows},
|
||||
|
||||
Val{"bs-enclosed and trailing literal quote", 0, OsTypeWindows},
|
||||
Val{"\\%{a}\\\\\\^\"", "\\hi\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{aa}\\\\\\^\"", "\\\\\"hi ho\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{b}\\\\\\^\"", "\\h\\i\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{c}\\\\\\^\"", "\\\\hi\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{d}\\\\\\^\"", "\\hi\\\\\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{ba}\\\\\\^\"", "\\\\\"h\\i ho\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{ca}\\\\\\^\"", "\\\\\"\\hi ho\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{da}\\\\\\^\"", "\\\\\"hi ho\\\\\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{e}\\\\\\^\"", "\\\\\"h\"\\^\"\"i\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{f}\\\\\\^\"", "\\\\\"\"\\^\"\"hi\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{g}\\\\\\^\"", "\\\\\"hi\"\\^\"\"\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{h}\\\\\\^\"", "\\\\\"h\\\\\"\\^\"\"i\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{i}\\\\\\^\"", "\\\\\"\\\\\"\\^\"\"hi\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{j}\\\\\\^\"", "\\\\\"hi\\\\\"\\^\"\"\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{x}\\\\\\^\"", "\\\\\\\\\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{y}\\\\\\^\"", "\\\\\"\"\\^\"\"\"\\\\\\^\"", OsTypeWindows},
|
||||
Val{"\\%{z}\\\\\\^\"", "\\\\\\\\\\^\"", OsTypeWindows},
|
||||
|
||||
Val{"bs-enclosed and trailing unclosed quote", 0, OsTypeWindows},
|
||||
Val{"\\%{a}\\\\\"", "\\hi\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{aa}\\\\\"", "\\\\\"hi ho\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{b}\\\\\"", "\\h\\i\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{c}\\\\\"", "\\\\hi\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{d}\\\\\"", "\\hi\\\\\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{ba}\\\\\"", "\\\\\"h\\i ho\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{ca}\\\\\"", "\\\\\"\\hi ho\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{da}\\\\\"", "\\\\\"hi ho\\\\\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{e}\\\\\"", "\\\\\"h\"\\^\"\"i\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{f}\\\\\"", "\\\\\"\"\\^\"\"hi\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{g}\\\\\"", "\\\\\"hi\"\\^\"\"\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{h}\\\\\"", "\\\\\"h\\\\\"\\^\"\"i\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{i}\\\\\"", "\\\\\"\\\\\"\\^\"\"hi\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{j}\\\\\"", "\\\\\"hi\\\\\"\\^\"\"\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{x}\\\\\"", "\\\\\\\\\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{y}\\\\\"", "\\\\\"\"\\^\"\"\"\\\\\"", OsTypeWindows},
|
||||
Val{"\\%{z}\\\\\"", "\\\\\\\\\"", OsTypeWindows},
|
||||
|
||||
Val{"multi-var", 0, OsTypeWindows},
|
||||
Val{"%{x}%{y}%{z}", "\\\\\"\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"%{x}%{z}%{y}%{z}", "\\\\\"\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"%{x}%{z}%{y}", "\\\\\"\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"%{x}\\^\"%{z}", "\\\\\\^\"", OsTypeWindows},
|
||||
Val{"%{x}%{z}\\^\"%{z}", "\\\\\\^\"", OsTypeWindows},
|
||||
Val{"%{x}%{z}\\^\"", "\\\\\\^\"", OsTypeWindows},
|
||||
Val{"%{x}\\%{z}", "\\\\", OsTypeWindows},
|
||||
Val{"%{x}%{z}\\%{z}", "\\\\", OsTypeWindows},
|
||||
Val{"%{x}%{z}\\", "\\\\", OsTypeWindows},
|
||||
Val{"%{aa}%{a}", "\"hi hohi\"", OsTypeWindows},
|
||||
Val{"%{aa}%{aa}", "\"hi hohi ho\"", OsTypeWindows},
|
||||
Val{"%{aa}:%{aa}", "\"hi ho\":\"hi ho\"", OsTypeWindows},
|
||||
Val{"hallo ^|%{aa}^|", "hallo ^|\"hi ho\"^|", OsTypeWindows},
|
||||
|
||||
Val{"quoted multi-var", 0, OsTypeWindows},
|
||||
Val{"\"%{x}%{y}%{z}\"", "\"\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{x}%{z}%{y}%{z}\"", "\"\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{x}%{z}%{y}\"", "\"\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{x}\"^\"\"%{z}\"", "\"\\\\\"^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{x}%{z}\"^\"\"%{z}\"", "\"\\\\\"^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{x}%{z}\"^\"\"\"", "\"\\\\\"^\"\"\"", OsTypeWindows},
|
||||
Val{"\"%{x}\\%{z}\"", "\"\\\\\\\\\"", OsTypeWindows},
|
||||
Val{"\"%{x}%{z}\\%{z}\"", "\"\\\\\\\\\"", OsTypeWindows},
|
||||
Val{"\"%{x}%{z}\\\\\"", "\"\\\\\\\\\"", OsTypeWindows},
|
||||
Val{"\"%{aa}%{a}\"", "\"hi hohi\"", OsTypeWindows},
|
||||
Val{"\"%{aa}%{aa}\"", "\"hi hohi ho\"", OsTypeWindows},
|
||||
Val{"\"%{aa}:%{aa}\"", "\"hi ho:hi ho\"", OsTypeWindows},
|
||||
|
||||
Val{"plain", 0, OsTypeLinux},
|
||||
Val{"%{a}", "hi", OsTypeLinux},
|
||||
Val{"%{b}", "'hi ho'", OsTypeLinux},
|
||||
Val{"%{c}", "'&special;'", OsTypeLinux},
|
||||
Val{"%{d}", "'h\\i'", OsTypeLinux},
|
||||
Val{"%{e}", "'h\"i'", OsTypeLinux},
|
||||
Val{"%{f}", "'h'\\''i'", OsTypeLinux},
|
||||
Val{"%{z}", "''", OsTypeLinux},
|
||||
Val{"\\%{z}%{z}", "\\%{z}%{z}", OsTypeLinux}, // stupid user check
|
||||
|
||||
Val{"single-quoted", 0, OsTypeLinux},
|
||||
Val{"'%{a}'", "'hi'", OsTypeLinux},
|
||||
Val{"'%{b}'", "'hi ho'", OsTypeLinux},
|
||||
Val{"'%{c}'", "'&special;'", OsTypeLinux},
|
||||
Val{"'%{d}'", "'h\\i'", OsTypeLinux},
|
||||
Val{"'%{e}'", "'h\"i'", OsTypeLinux},
|
||||
Val{"'%{f}'", "'h'\\''i'", OsTypeLinux},
|
||||
Val{"'%{z}'", "''", OsTypeLinux},
|
||||
|
||||
Val{"double-quoted", 0, OsTypeLinux},
|
||||
Val{"\"%{a}\"", "\"hi\"", OsTypeLinux},
|
||||
Val{"\"%{b}\"", "\"hi ho\"", OsTypeLinux},
|
||||
Val{"\"%{c}\"", "\"&special;\"", OsTypeLinux},
|
||||
Val{"\"%{d}\"", "\"h\\\\i\"", OsTypeLinux},
|
||||
Val{"\"%{e}\"", "\"h\\\"i\"", OsTypeLinux},
|
||||
Val{"\"%{f}\"", "\"h'i\"", OsTypeLinux},
|
||||
Val{"\"%{z}\"", "\"\"", OsTypeLinux},
|
||||
|
||||
Val{"complex", 0, OsTypeLinux},
|
||||
Val{"echo \"$(echo %{a})\"", "echo \"$(echo hi)\"", OsTypeLinux},
|
||||
Val{"echo \"$(echo %{b})\"", "echo \"$(echo 'hi ho')\"", OsTypeLinux},
|
||||
Val{"echo \"$(echo \"%{a}\")\"", "echo \"$(echo \"hi\")\"", OsTypeLinux},
|
||||
// These make no sense shell-wise, but they test expando nesting
|
||||
Val{"echo \"%{echo %{a}}\"", "echo \"%{echo hi}\"", OsTypeLinux},
|
||||
Val{"echo \"%{echo %{b}}\"", "echo \"%{echo hi ho}\"", OsTypeLinux},
|
||||
Val{"echo \"%{echo \"%{a}\"}\"", "echo \"%{echo \"hi\"}\"", OsTypeLinux}};
|
||||
|
||||
const char *title = 0;
|
||||
for (const auto &val : vals) {
|
||||
if (!val.out) {
|
||||
title = val.in;
|
||||
} else {
|
||||
QString name
|
||||
= QString("%1: %2 (%3)")
|
||||
.arg(title, val.in, val.os == OsTypeWindows ? "windows" : "linux");
|
||||
QTest::newRow(name.toLatin1())
|
||||
<< QString::fromLatin1(val.in) << QString::fromLatin1(val.out) << val.os;
|
||||
QTest::newRow(("padded " + name).toLatin1())
|
||||
<< QString(sp + QString::fromLatin1(val.in) + sp)
|
||||
<< QString(sp + QString::fromLatin1(val.out) + sp) << val.os;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void expandProcessArgs()
|
||||
{
|
||||
QFETCH(QString, in);
|
||||
QFETCH(QString, out);
|
||||
QFETCH(OsType, os);
|
||||
|
||||
MacroExpander expander;
|
||||
|
||||
if (os == Utils::OsTypeWindows) {
|
||||
expander.registerVariable("a", "", [] { return "hi"; });
|
||||
expander.registerVariable("aa", "", [] { return "hi ho"; });
|
||||
expander.registerVariable("b", "", [] { return "h\\i"; });
|
||||
expander.registerVariable("c", "", [] { return "\\hi"; });
|
||||
expander.registerVariable("d", "", [] { return "hi\\"; });
|
||||
expander.registerVariable("ba", "", [] { return "h\\i ho"; });
|
||||
expander.registerVariable("ca", "", [] { return "\\hi ho"; });
|
||||
expander.registerVariable("da", "", [] { return "hi ho\\"; });
|
||||
expander.registerVariable("e", "", [] { return "h\"i"; });
|
||||
expander.registerVariable("f", "", [] { return "\"hi"; });
|
||||
expander.registerVariable("g", "", [] { return "hi\""; });
|
||||
expander.registerVariable("h", "", [] { return "h\\\"i"; });
|
||||
expander.registerVariable("i", "", [] { return "\\\"hi"; });
|
||||
expander.registerVariable("j", "", [] { return "hi\\\""; });
|
||||
expander.registerVariable("k", "", [] { return "&special;"; });
|
||||
expander.registerVariable("x", "", [] { return "\\"; });
|
||||
expander.registerVariable("y", "", [] { return "\""; });
|
||||
expander.registerVariable("z", "", [] { return ""; });
|
||||
} else {
|
||||
expander.registerVariable("a", "", [] { return "hi"; });
|
||||
expander.registerVariable("b", "", [] { return "hi ho"; });
|
||||
expander.registerVariable("c", "", [] { return "&special;"; });
|
||||
expander.registerVariable("d", "", [] { return "h\\i"; });
|
||||
expander.registerVariable("e", "", [] { return "h\"i"; });
|
||||
expander.registerVariable("f", "", [] { return "h'i"; });
|
||||
expander.registerVariable("z", "", [] { return ""; });
|
||||
}
|
||||
|
||||
QCOMPARE(expander.expandProcessArgs(in, os), out);
|
||||
}
|
||||
|
||||
void testMacroExpander_data()
|
||||
{
|
||||
QTest::addColumn<QString>("in");
|
||||
QTest::addColumn<QString>("out");
|
||||
|
||||
struct Val
|
||||
{
|
||||
const char *in;
|
||||
const char *out;
|
||||
};
|
||||
|
||||
const std::array vals = {
|
||||
Val{"text", "text"},
|
||||
Val{"%{a}", "hi"},
|
||||
Val{"%%{a}", "%hi"},
|
||||
Val{"%%%{a}", "%%hi"},
|
||||
Val{"%{b}", "%{b}"},
|
||||
Val{"pre%{a}", "prehi"},
|
||||
Val{"%{a}post", "hipost"},
|
||||
Val{"pre%{a}post", "prehipost"},
|
||||
Val{"%{a}%{a}", "hihi"},
|
||||
Val{"%{a}text%{a}", "hitexthi"},
|
||||
Val{"%{foo}%{a}text%{a}", "ahitexthi"},
|
||||
Val{"%{}{a}", "%{a}"},
|
||||
Val{"%{}", "%"},
|
||||
Val{"test%{}", "test%"},
|
||||
Val{"%{}test", "%test"},
|
||||
Val{"%{abc", "%{abc"},
|
||||
Val{"%{%{a}", "%{hi"},
|
||||
Val{"%{%{a}}", "ho"},
|
||||
Val{"%{%{a}}}post", "ho}post"},
|
||||
Val{"%{hi%{a}}", "bar"},
|
||||
Val{"%{hi%{%{foo}}}", "bar"},
|
||||
Val{"%{hihi/b/c}", "car"},
|
||||
Val{"%{hihi/a/}", "br"}, // empty replacement
|
||||
Val{"%{hihi/b}", "bar"}, // incomplete substitution
|
||||
Val{"%{hihi/./c}", "car"},
|
||||
Val{"%{hihi//./c}", "ccc"},
|
||||
Val{"%{hihi/(.)(.)r/\\2\\1c}", "abc"}, // no escape for capture groups
|
||||
Val{"%{hihi/b/c/d}", "c/dar"},
|
||||
Val{"%{hihi/a/e{\\}e}", "be{}er"}, // escape closing brace
|
||||
Val{"%{JS:with \\} inside}", "yay"}, // escape closing brace also in JS:
|
||||
Val{"%{JS:literal%\\{}", "hurray"},
|
||||
Val{"%{slash/o\\/b/ol's c}", "fool's car"},
|
||||
Val{"%{sl\\/sh/(.)(a)(.)/\\2\\1\\3as}", "salsash"}, // escape in variable name
|
||||
Val{"%{JS:foo/b/c}", "%{JS:foo/b/c}"}, // No replacement for JS (all considered varName)
|
||||
Val{"%{%{a}%{a}/b/c}", "car"},
|
||||
Val{"%{nonsense:-sense}", "sense"},
|
||||
};
|
||||
|
||||
for (const auto &val : vals)
|
||||
QTest::newRow(val.in) << QString::fromLatin1(val.in) << QString::fromLatin1(val.out);
|
||||
}
|
||||
|
||||
void testMacroExpander()
|
||||
{
|
||||
QFETCH(QString, in);
|
||||
QFETCH(QString, out);
|
||||
|
||||
MacroExpander expander;
|
||||
expander.registerVariable("foo", "", [] { return "a"; });
|
||||
expander.registerVariable("a", "", [] { return "hi"; });
|
||||
expander.registerVariable("hi", "", [] { return "ho"; });
|
||||
expander.registerVariable("hihi", "", [] { return "bar"; });
|
||||
expander.registerVariable("slash", "", [] { return "foo/bar"; });
|
||||
expander.registerVariable("sl/sh", "", [] { return "slash"; });
|
||||
expander.registerVariable("JS:foor", "", [] { return "bar"; });
|
||||
expander.registerVariable("JS:with } inside", "", [] { return "yay"; });
|
||||
expander.registerVariable("JS:literal%{", "", [] { return "hurray"; });
|
||||
|
||||
QCOMPARE(expander.expand(in), out);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -66,29 +66,6 @@ protected:
|
||||
int MessageHandler::s_destroyCount = 0;
|
||||
QtMessageHandler MessageHandler::s_oldMessageHandler = 0;
|
||||
|
||||
class MacroMapExpander : public AbstractMacroExpander {
|
||||
public:
|
||||
bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander*> &seen)
|
||||
override
|
||||
{
|
||||
// loop prevention
|
||||
const int count = seen.count();
|
||||
seen.insert(this);
|
||||
if (seen.count() == count)
|
||||
return false;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
static constexpr char s_skipTerminateOnWindows[] =
|
||||
"Windows implementation of this test is lacking handling of WM_CLOSE message.";
|
||||
|
||||
@@ -135,8 +112,6 @@ private slots:
|
||||
void prepareArgs();
|
||||
void prepareArgsEnv_data();
|
||||
void prepareArgsEnv();
|
||||
void expandMacros_data();
|
||||
void expandMacros();
|
||||
void iterations_data();
|
||||
void iterations();
|
||||
void iteratorEditsWindows();
|
||||
@@ -181,8 +156,6 @@ private:
|
||||
Environment envWindows;
|
||||
Environment envLinux;
|
||||
|
||||
MacroMapExpander mxWin;
|
||||
MacroMapExpander mxUnix;
|
||||
QString homeStr;
|
||||
QString home;
|
||||
|
||||
@@ -206,38 +179,6 @@ void tst_Process::initTestCase()
|
||||
env << "empty=" << "word=hi" << "words=hi ho" << "spacedwords= hi ho sucker ";
|
||||
envWindows = Environment(env, OsTypeWindows);
|
||||
envLinux = Environment(env, OsTypeLinux);
|
||||
|
||||
mxWin.insert("a", "hi");
|
||||
mxWin.insert("aa", "hi ho");
|
||||
|
||||
mxWin.insert("b", "h\\i");
|
||||
mxWin.insert("c", "\\hi");
|
||||
mxWin.insert("d", "hi\\");
|
||||
mxWin.insert("ba", "h\\i ho");
|
||||
mxWin.insert("ca", "\\hi ho");
|
||||
mxWin.insert("da", "hi ho\\");
|
||||
|
||||
mxWin.insert("e", "h\"i");
|
||||
mxWin.insert("f", "\"hi");
|
||||
mxWin.insert("g", "hi\"");
|
||||
|
||||
mxWin.insert("h", "h\\\"i");
|
||||
mxWin.insert("i", "\\\"hi");
|
||||
mxWin.insert("j", "hi\\\"");
|
||||
|
||||
mxWin.insert("k", "&special;");
|
||||
|
||||
mxWin.insert("x", "\\");
|
||||
mxWin.insert("y", "\"");
|
||||
mxWin.insert("z", "");
|
||||
|
||||
mxUnix.insert("a", "hi");
|
||||
mxUnix.insert("b", "hi ho");
|
||||
mxUnix.insert("c", "&special;");
|
||||
mxUnix.insert("d", "h\\i");
|
||||
mxUnix.insert("e", "h\"i");
|
||||
mxUnix.insert("f", "h'i");
|
||||
mxUnix.insert("z", "");
|
||||
}
|
||||
|
||||
void tst_Process::cleanupTestCase()
|
||||
@@ -550,252 +491,7 @@ void tst_Process::prepareArgsEnv()
|
||||
QCOMPARE(outstr, out);
|
||||
}
|
||||
|
||||
void tst_Process::expandMacros_data()
|
||||
|
||||
{
|
||||
QTest::addColumn<QString>("in");
|
||||
QTest::addColumn<QString>("out");
|
||||
QTest::addColumn<OsType>("os");
|
||||
QChar sp(QLatin1Char(' '));
|
||||
|
||||
static const struct {
|
||||
const char * const in;
|
||||
const char * const out;
|
||||
OsType os;
|
||||
} vals[] = {
|
||||
{"plain", 0, OsTypeWindows},
|
||||
{"%{a}", "hi", OsTypeWindows},
|
||||
{"%{aa}", "\"hi ho\"", OsTypeWindows},
|
||||
{"%{b}", "h\\i", OsTypeWindows},
|
||||
{"%{c}", "\\hi", OsTypeWindows},
|
||||
{"%{d}", "hi\\", OsTypeWindows},
|
||||
{"%{ba}", "\"h\\i ho\"", OsTypeWindows},
|
||||
{"%{ca}", "\"\\hi ho\"", OsTypeWindows},
|
||||
{"%{da}", "\"hi ho\\\\\"", OsTypeWindows}, // or "\"hi ho\"\\"
|
||||
{"%{e}", "\"h\"\\^\"\"i\"", OsTypeWindows},
|
||||
{"%{f}", "\"\"\\^\"\"hi\"", OsTypeWindows},
|
||||
{"%{g}", "\"hi\"\\^\"\"\"", OsTypeWindows},
|
||||
{"%{h}", "\"h\\\\\"\\^\"\"i\"", OsTypeWindows},
|
||||
{"%{i}", "\"\\\\\"\\^\"\"hi\"", OsTypeWindows},
|
||||
{"%{j}", "\"hi\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
{"%{k}", "\"&special;\"", OsTypeWindows},
|
||||
{"%{x}", "\\", OsTypeWindows},
|
||||
{"%{y}", "\"\"\\^\"\"\"", OsTypeWindows},
|
||||
{"%{z}", "\"\"", OsTypeWindows},
|
||||
{"^%{z}%{z}", "^%{z}%{z}", OsTypeWindows}, // stupid user check
|
||||
|
||||
{"quoted", 0, OsTypeWindows},
|
||||
{"\"%{a}\"", "\"hi\"", OsTypeWindows},
|
||||
{"\"%{aa}\"", "\"hi ho\"", OsTypeWindows},
|
||||
{"\"%{b}\"", "\"h\\i\"", OsTypeWindows},
|
||||
{"\"%{c}\"", "\"\\hi\"", OsTypeWindows},
|
||||
{"\"%{d}\"", "\"hi\\\\\"", OsTypeWindows},
|
||||
{"\"%{ba}\"", "\"h\\i ho\"", OsTypeWindows},
|
||||
{"\"%{ca}\"", "\"\\hi ho\"", OsTypeWindows},
|
||||
{"\"%{da}\"", "\"hi ho\\\\\"", OsTypeWindows},
|
||||
{"\"%{e}\"", "\"h\"\\^\"\"i\"", OsTypeWindows},
|
||||
{"\"%{f}\"", "\"\"\\^\"\"hi\"", OsTypeWindows},
|
||||
{"\"%{g}\"", "\"hi\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\"%{h}\"", "\"h\\\\\"\\^\"\"i\"", OsTypeWindows},
|
||||
{"\"%{i}\"", "\"\\\\\"\\^\"\"hi\"", OsTypeWindows},
|
||||
{"\"%{j}\"", "\"hi\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\"%{k}\"", "\"&special;\"", OsTypeWindows},
|
||||
{"\"%{x}\"", "\"\\\\\"", OsTypeWindows},
|
||||
{"\"%{y}\"", "\"\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\"%{z}\"", "\"\"", OsTypeWindows},
|
||||
|
||||
{"leading bs", 0, OsTypeWindows},
|
||||
{"\\%{a}", "\\hi", OsTypeWindows},
|
||||
{"\\%{aa}", "\\\\\"hi ho\"", OsTypeWindows},
|
||||
{"\\%{b}", "\\h\\i", OsTypeWindows},
|
||||
{"\\%{c}", "\\\\hi", OsTypeWindows},
|
||||
{"\\%{d}", "\\hi\\", OsTypeWindows},
|
||||
{"\\%{ba}", "\\\\\"h\\i ho\"", OsTypeWindows},
|
||||
{"\\%{ca}", "\\\\\"\\hi ho\"", OsTypeWindows},
|
||||
{"\\%{da}", "\\\\\"hi ho\\\\\"", OsTypeWindows},
|
||||
{"\\%{e}", "\\\\\"h\"\\^\"\"i\"", OsTypeWindows},
|
||||
{"\\%{f}", "\\\\\"\"\\^\"\"hi\"", OsTypeWindows},
|
||||
{"\\%{g}", "\\\\\"hi\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\\%{h}", "\\\\\"h\\\\\"\\^\"\"i\"", OsTypeWindows},
|
||||
{"\\%{i}", "\\\\\"\\\\\"\\^\"\"hi\"", OsTypeWindows},
|
||||
{"\\%{j}", "\\\\\"hi\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\\%{x}", "\\\\", OsTypeWindows},
|
||||
{"\\%{y}", "\\\\\"\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\\%{z}", "\\", OsTypeWindows},
|
||||
|
||||
{"trailing bs", 0, OsTypeWindows},
|
||||
{"%{a}\\", "hi\\", OsTypeWindows},
|
||||
{"%{aa}\\", "\"hi ho\"\\", OsTypeWindows},
|
||||
{"%{b}\\", "h\\i\\", OsTypeWindows},
|
||||
{"%{c}\\", "\\hi\\", OsTypeWindows},
|
||||
{"%{d}\\", "hi\\\\", OsTypeWindows},
|
||||
{"%{ba}\\", "\"h\\i ho\"\\", OsTypeWindows},
|
||||
{"%{ca}\\", "\"\\hi ho\"\\", OsTypeWindows},
|
||||
{"%{da}\\", "\"hi ho\\\\\"\\", OsTypeWindows},
|
||||
{"%{e}\\", "\"h\"\\^\"\"i\"\\", OsTypeWindows},
|
||||
{"%{f}\\", "\"\"\\^\"\"hi\"\\", OsTypeWindows},
|
||||
{"%{g}\\", "\"hi\"\\^\"\"\"\\", OsTypeWindows},
|
||||
{"%{h}\\", "\"h\\\\\"\\^\"\"i\"\\", OsTypeWindows},
|
||||
{"%{i}\\", "\"\\\\\"\\^\"\"hi\"\\", OsTypeWindows},
|
||||
{"%{j}\\", "\"hi\\\\\"\\^\"\"\"\\", OsTypeWindows},
|
||||
{"%{x}\\", "\\\\", OsTypeWindows},
|
||||
{"%{y}\\", "\"\"\\^\"\"\"\\", OsTypeWindows},
|
||||
{"%{z}\\", "\\", OsTypeWindows},
|
||||
|
||||
{"bs-enclosed", 0, OsTypeWindows},
|
||||
{"\\%{a}\\", "\\hi\\", OsTypeWindows},
|
||||
{"\\%{aa}\\", "\\\\\"hi ho\"\\", OsTypeWindows},
|
||||
{"\\%{b}\\", "\\h\\i\\", OsTypeWindows},
|
||||
{"\\%{c}\\", "\\\\hi\\", OsTypeWindows},
|
||||
{"\\%{d}\\", "\\hi\\\\", OsTypeWindows},
|
||||
{"\\%{ba}\\", "\\\\\"h\\i ho\"\\", OsTypeWindows},
|
||||
{"\\%{ca}\\", "\\\\\"\\hi ho\"\\", OsTypeWindows},
|
||||
{"\\%{da}\\", "\\\\\"hi ho\\\\\"\\", OsTypeWindows},
|
||||
{"\\%{e}\\", "\\\\\"h\"\\^\"\"i\"\\", OsTypeWindows},
|
||||
{"\\%{f}\\", "\\\\\"\"\\^\"\"hi\"\\", OsTypeWindows},
|
||||
{"\\%{g}\\", "\\\\\"hi\"\\^\"\"\"\\", OsTypeWindows},
|
||||
{"\\%{h}\\", "\\\\\"h\\\\\"\\^\"\"i\"\\", OsTypeWindows},
|
||||
{"\\%{i}\\", "\\\\\"\\\\\"\\^\"\"hi\"\\", OsTypeWindows},
|
||||
{"\\%{j}\\", "\\\\\"hi\\\\\"\\^\"\"\"\\", OsTypeWindows},
|
||||
{"\\%{x}\\", "\\\\\\", OsTypeWindows},
|
||||
{"\\%{y}\\", "\\\\\"\"\\^\"\"\"\\", OsTypeWindows},
|
||||
{"\\%{z}\\", "\\\\", OsTypeWindows},
|
||||
|
||||
{"bs-enclosed and trailing literal quote", 0, OsTypeWindows},
|
||||
{"\\%{a}\\\\\\^\"", "\\hi\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{aa}\\\\\\^\"", "\\\\\"hi ho\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{b}\\\\\\^\"", "\\h\\i\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{c}\\\\\\^\"", "\\\\hi\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{d}\\\\\\^\"", "\\hi\\\\\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{ba}\\\\\\^\"", "\\\\\"h\\i ho\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{ca}\\\\\\^\"", "\\\\\"\\hi ho\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{da}\\\\\\^\"", "\\\\\"hi ho\\\\\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{e}\\\\\\^\"", "\\\\\"h\"\\^\"\"i\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{f}\\\\\\^\"", "\\\\\"\"\\^\"\"hi\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{g}\\\\\\^\"", "\\\\\"hi\"\\^\"\"\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{h}\\\\\\^\"", "\\\\\"h\\\\\"\\^\"\"i\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{i}\\\\\\^\"", "\\\\\"\\\\\"\\^\"\"hi\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{j}\\\\\\^\"", "\\\\\"hi\\\\\"\\^\"\"\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{x}\\\\\\^\"", "\\\\\\\\\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{y}\\\\\\^\"", "\\\\\"\"\\^\"\"\"\\\\\\^\"", OsTypeWindows},
|
||||
{"\\%{z}\\\\\\^\"", "\\\\\\\\\\^\"", OsTypeWindows},
|
||||
|
||||
{"bs-enclosed and trailing unclosed quote", 0, OsTypeWindows},
|
||||
{"\\%{a}\\\\\"", "\\hi\\\\\"", OsTypeWindows},
|
||||
{"\\%{aa}\\\\\"", "\\\\\"hi ho\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{b}\\\\\"", "\\h\\i\\\\\"", OsTypeWindows},
|
||||
{"\\%{c}\\\\\"", "\\\\hi\\\\\"", OsTypeWindows},
|
||||
{"\\%{d}\\\\\"", "\\hi\\\\\\\\\"", OsTypeWindows},
|
||||
{"\\%{ba}\\\\\"", "\\\\\"h\\i ho\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{ca}\\\\\"", "\\\\\"\\hi ho\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{da}\\\\\"", "\\\\\"hi ho\\\\\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{e}\\\\\"", "\\\\\"h\"\\^\"\"i\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{f}\\\\\"", "\\\\\"\"\\^\"\"hi\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{g}\\\\\"", "\\\\\"hi\"\\^\"\"\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{h}\\\\\"", "\\\\\"h\\\\\"\\^\"\"i\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{i}\\\\\"", "\\\\\"\\\\\"\\^\"\"hi\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{j}\\\\\"", "\\\\\"hi\\\\\"\\^\"\"\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{x}\\\\\"", "\\\\\\\\\\\\\"", OsTypeWindows},
|
||||
{"\\%{y}\\\\\"", "\\\\\"\"\\^\"\"\"\\\\\"", OsTypeWindows},
|
||||
{"\\%{z}\\\\\"", "\\\\\\\\\"", OsTypeWindows},
|
||||
|
||||
{"multi-var", 0, OsTypeWindows},
|
||||
{"%{x}%{y}%{z}", "\\\\\"\"\\^\"\"\"", OsTypeWindows},
|
||||
{"%{x}%{z}%{y}%{z}", "\\\\\"\"\\^\"\"\"", OsTypeWindows},
|
||||
{"%{x}%{z}%{y}", "\\\\\"\"\\^\"\"\"", OsTypeWindows},
|
||||
{"%{x}\\^\"%{z}", "\\\\\\^\"", OsTypeWindows},
|
||||
{"%{x}%{z}\\^\"%{z}", "\\\\\\^\"", OsTypeWindows},
|
||||
{"%{x}%{z}\\^\"", "\\\\\\^\"", OsTypeWindows},
|
||||
{"%{x}\\%{z}", "\\\\", OsTypeWindows},
|
||||
{"%{x}%{z}\\%{z}", "\\\\", OsTypeWindows},
|
||||
{"%{x}%{z}\\", "\\\\", OsTypeWindows},
|
||||
{"%{aa}%{a}", "\"hi hohi\"", OsTypeWindows},
|
||||
{"%{aa}%{aa}", "\"hi hohi ho\"", OsTypeWindows},
|
||||
{"%{aa}:%{aa}", "\"hi ho\":\"hi ho\"", OsTypeWindows},
|
||||
{"hallo ^|%{aa}^|", "hallo ^|\"hi ho\"^|", OsTypeWindows},
|
||||
|
||||
{"quoted multi-var", 0, OsTypeWindows},
|
||||
{"\"%{x}%{y}%{z}\"", "\"\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\"%{x}%{z}%{y}%{z}\"", "\"\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\"%{x}%{z}%{y}\"", "\"\\\\\"\\^\"\"\"", OsTypeWindows},
|
||||
{"\"%{x}\"^\"\"%{z}\"", "\"\\\\\"^\"\"\"", OsTypeWindows},
|
||||
{"\"%{x}%{z}\"^\"\"%{z}\"", "\"\\\\\"^\"\"\"", OsTypeWindows},
|
||||
{"\"%{x}%{z}\"^\"\"\"", "\"\\\\\"^\"\"\"", OsTypeWindows},
|
||||
{"\"%{x}\\%{z}\"", "\"\\\\\\\\\"", OsTypeWindows},
|
||||
{"\"%{x}%{z}\\%{z}\"", "\"\\\\\\\\\"", OsTypeWindows},
|
||||
{"\"%{x}%{z}\\\\\"", "\"\\\\\\\\\"", OsTypeWindows},
|
||||
{"\"%{aa}%{a}\"", "\"hi hohi\"", OsTypeWindows},
|
||||
{"\"%{aa}%{aa}\"", "\"hi hohi ho\"", OsTypeWindows},
|
||||
{"\"%{aa}:%{aa}\"", "\"hi ho:hi ho\"", OsTypeWindows},
|
||||
|
||||
{"plain", 0, OsTypeLinux},
|
||||
{"%{a}", "hi", OsTypeLinux},
|
||||
{"%{b}", "'hi ho'", OsTypeLinux},
|
||||
{"%{c}", "'&special;'", OsTypeLinux},
|
||||
{"%{d}", "'h\\i'", OsTypeLinux},
|
||||
{"%{e}", "'h\"i'", OsTypeLinux},
|
||||
{"%{f}", "'h'\\''i'", OsTypeLinux},
|
||||
{"%{z}", "''", OsTypeLinux},
|
||||
{"\\%{z}%{z}", "\\%{z}%{z}", OsTypeLinux}, // stupid user check
|
||||
|
||||
{"single-quoted", 0, OsTypeLinux},
|
||||
{"'%{a}'", "'hi'", OsTypeLinux},
|
||||
{"'%{b}'", "'hi ho'", OsTypeLinux},
|
||||
{"'%{c}'", "'&special;'", OsTypeLinux},
|
||||
{"'%{d}'", "'h\\i'", OsTypeLinux},
|
||||
{"'%{e}'", "'h\"i'", OsTypeLinux},
|
||||
{"'%{f}'", "'h'\\''i'", OsTypeLinux},
|
||||
{"'%{z}'", "''", OsTypeLinux},
|
||||
|
||||
{"double-quoted", 0, OsTypeLinux},
|
||||
{"\"%{a}\"", "\"hi\"", OsTypeLinux},
|
||||
{"\"%{b}\"", "\"hi ho\"", OsTypeLinux},
|
||||
{"\"%{c}\"", "\"&special;\"", OsTypeLinux},
|
||||
{"\"%{d}\"", "\"h\\\\i\"", OsTypeLinux},
|
||||
{"\"%{e}\"", "\"h\\\"i\"", OsTypeLinux},
|
||||
{"\"%{f}\"", "\"h'i\"", OsTypeLinux},
|
||||
{"\"%{z}\"", "\"\"", OsTypeLinux},
|
||||
|
||||
{"complex", 0, OsTypeLinux},
|
||||
{"echo \"$(echo %{a})\"", "echo \"$(echo hi)\"", OsTypeLinux},
|
||||
{"echo \"$(echo %{b})\"", "echo \"$(echo 'hi ho')\"", OsTypeLinux},
|
||||
{"echo \"$(echo \"%{a}\")\"", "echo \"$(echo \"hi\")\"", OsTypeLinux},
|
||||
// These make no sense shell-wise, but they test expando nesting
|
||||
{"echo \"%{echo %{a}}\"", "echo \"%{echo hi}\"", OsTypeLinux},
|
||||
{"echo \"%{echo %{b}}\"", "echo \"%{echo hi ho}\"", OsTypeLinux},
|
||||
{"echo \"%{echo \"%{a}\"}\"", "echo \"%{echo \"hi\"}\"", OsTypeLinux },
|
||||
};
|
||||
|
||||
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];
|
||||
snprintf(buf, 80, "%s: %s", title, vals[i].in);
|
||||
QTest::newRow(buf) << QString::fromLatin1(vals[i].in)
|
||||
<< QString::fromLatin1(vals[i].out)
|
||||
<< vals[i].os;
|
||||
snprintf(buf, 80, "padded %s: %s", title, vals[i].in);
|
||||
QTest::newRow(buf) << QString(sp + QString::fromLatin1(vals[i].in) + sp)
|
||||
<< QString(sp + QString::fromLatin1(vals[i].out) + sp)
|
||||
<< vals[i].os;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Process::expandMacros()
|
||||
{
|
||||
QFETCH(QString, in);
|
||||
QFETCH(QString, out);
|
||||
QFETCH(OsType, os);
|
||||
|
||||
if (os == OsTypeWindows)
|
||||
ProcessArgs::expandMacros(&in, &mxWin, os);
|
||||
else
|
||||
ProcessArgs::expandMacros(&in, &mxUnix, os);
|
||||
QCOMPARE(in, out);
|
||||
}
|
||||
|
||||
void tst_Process::iterations_data()
|
||||
{
|
||||
|
@@ -10,66 +10,12 @@
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
class TestMacroExpander : public Utils::AbstractMacroExpander
|
||||
{
|
||||
public:
|
||||
bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander*> &seen)
|
||||
override
|
||||
{
|
||||
// loop prevention
|
||||
const int count = seen.count();
|
||||
seen.insert(this);
|
||||
if (seen.count() == count)
|
||||
return false;
|
||||
|
||||
if (name == QLatin1String("foo")) {
|
||||
*ret = QLatin1String("a");
|
||||
return true;
|
||||
}
|
||||
if (name == QLatin1String("a")) {
|
||||
*ret = QLatin1String("hi");
|
||||
return true;
|
||||
}
|
||||
if (name == QLatin1String("hi")) {
|
||||
*ret = QLatin1String("ho");
|
||||
return true;
|
||||
}
|
||||
if (name == QLatin1String("hihi")) {
|
||||
*ret = QLatin1String("bar");
|
||||
return true;
|
||||
}
|
||||
if (name == "slash") {
|
||||
*ret = "foo/bar";
|
||||
return true;
|
||||
}
|
||||
if (name == "sl/sh") {
|
||||
*ret = "slash";
|
||||
return true;
|
||||
}
|
||||
if (name == "JS:foo") {
|
||||
*ret = "bar";
|
||||
return true;
|
||||
}
|
||||
if (name == "JS:with } inside") {
|
||||
*ret = "yay";
|
||||
return true;
|
||||
}
|
||||
if (name == "JS:literal%{") {
|
||||
*ret = "hurray";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class tst_StringUtils : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testWithTildeHomePath();
|
||||
void testMacroExpander_data();
|
||||
void testMacroExpander();
|
||||
void testStripAccelerator_data();
|
||||
void testStripAccelerator();
|
||||
void testParseUsedPortFromNetstatOutput_data();
|
||||
@@ -84,9 +30,6 @@ private slots:
|
||||
void testSplitAtFirst();
|
||||
void testAsciify_data();
|
||||
void testAsciify();
|
||||
|
||||
private:
|
||||
TestMacroExpander mx;
|
||||
};
|
||||
|
||||
void tst_StringUtils::testWithTildeHomePath()
|
||||
@@ -118,68 +61,6 @@ void tst_StringUtils::testWithTildeHomePath()
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_StringUtils::testMacroExpander_data()
|
||||
|
||||
{
|
||||
QTest::addColumn<QString>("in");
|
||||
QTest::addColumn<QString>("out");
|
||||
|
||||
static const struct {
|
||||
const char * const in;
|
||||
const char * const out;
|
||||
} vals[] = {
|
||||
{"text", "text"},
|
||||
{"%{a}", "hi"},
|
||||
{"%%{a}", "%hi"},
|
||||
{"%%%{a}", "%%hi"},
|
||||
{"%{b}", "%{b}"},
|
||||
{"pre%{a}", "prehi"},
|
||||
{"%{a}post", "hipost"},
|
||||
{"pre%{a}post", "prehipost"},
|
||||
{"%{a}%{a}", "hihi"},
|
||||
{"%{a}text%{a}", "hitexthi"},
|
||||
{"%{foo}%{a}text%{a}", "ahitexthi"},
|
||||
{"%{}{a}", "%{a}"},
|
||||
{"%{}", "%"},
|
||||
{"test%{}", "test%"},
|
||||
{"%{}test", "%test"},
|
||||
{"%{abc", "%{abc"},
|
||||
{"%{%{a}", "%{hi"},
|
||||
{"%{%{a}}", "ho"},
|
||||
{"%{%{a}}}post", "ho}post"},
|
||||
{"%{hi%{a}}", "bar"},
|
||||
{"%{hi%{%{foo}}}", "bar"},
|
||||
{"%{hihi/b/c}", "car"},
|
||||
{"%{hihi/a/}", "br"}, // empty replacement
|
||||
{"%{hihi/b}", "bar"}, // incomplete substitution
|
||||
{"%{hihi/./c}", "car"},
|
||||
{"%{hihi//./c}", "ccc"},
|
||||
{"%{hihi/(.)(.)r/\\2\\1c}", "abc"}, // no escape for capture groups
|
||||
{"%{hihi/b/c/d}", "c/dar"},
|
||||
{"%{hihi/a/e{\\}e}", "be{}er"}, // escape closing brace
|
||||
{"%{JS:with \\} inside}", "yay"}, // escape closing brace also in JS:
|
||||
{"%{JS:literal%\\{}", "hurray"},
|
||||
{"%{slash/o\\/b/ol's c}", "fool's car"},
|
||||
{"%{sl\\/sh/(.)(a)(.)/\\2\\1\\3as}", "salsash"}, // escape in variable name
|
||||
{"%{JS:foo/b/c}", "%{JS:foo/b/c}"}, // No replacement for JS (all considered varName)
|
||||
{"%{%{a}%{a}/b/c}", "car"},
|
||||
{"%{nonsense:-sense}", "sense"},
|
||||
};
|
||||
|
||||
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_StringUtils::testMacroExpander()
|
||||
{
|
||||
QFETCH(QString, in);
|
||||
QFETCH(QString, out);
|
||||
|
||||
Utils::expandMacros(&in, &mx);
|
||||
QCOMPARE(in, out);
|
||||
}
|
||||
|
||||
void tst_StringUtils::testStripAccelerator_data()
|
||||
{
|
||||
QTest::addColumn<QString>("expected");
|
||||
|
Reference in New Issue
Block a user