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
|
* \return false if the string could not be parsed and therefore no safe
|
||||||
* substitution was possible
|
* 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;
|
QString str = *cmd;
|
||||||
if (str.isEmpty())
|
if (str.isEmpty())
|
||||||
@@ -775,7 +775,7 @@ bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType o
|
|||||||
QString rsts;
|
QString rsts;
|
||||||
int varLen;
|
int varLen;
|
||||||
int varPos = 0;
|
int varPos = 0;
|
||||||
if (!(varLen = mx->findMacro(str, &varPos, &rsts)))
|
if (!(varLen = findMacro(str, &varPos, &rsts)))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
@@ -839,7 +839,7 @@ bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType o
|
|||||||
str.replace(pos, varLen, rsts);
|
str.replace(pos, varLen, rsts);
|
||||||
pos += rsts.length();
|
pos += rsts.length();
|
||||||
varPos = pos;
|
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
|
// Don't leave immediately, as we may be in CrtNeedWord state which could
|
||||||
// be still resolved, or we may have inserted trailing backslashes.
|
// be still resolved, or we may have inserted trailing backslashes.
|
||||||
varPos = INT_MAX;
|
varPos = INT_MAX;
|
||||||
@@ -954,7 +954,7 @@ bool ProcessArgs::expandMacros(QString *cmd, AbstractMacroExpander *mx, OsType o
|
|||||||
str.replace(pos, varLen, rsts);
|
str.replace(pos, varLen, rsts);
|
||||||
pos += rsts.length();
|
pos += rsts.length();
|
||||||
varPos = pos;
|
varPos = pos;
|
||||||
if (!(varLen = mx->findMacro(str, &varPos, &rsts)))
|
if (!(varLen = findMacro(str, &varPos, &rsts)))
|
||||||
break;
|
break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@@ -59,9 +59,12 @@ public:
|
|||||||
static QStringList splitArgs(const QString &cmd, OsType osType,
|
static QStringList splitArgs(const QString &cmd, OsType osType,
|
||||||
bool abortOnMeta = false, SplitError *err = nullptr,
|
bool abortOnMeta = false, SplitError *err = nullptr,
|
||||||
const Environment *env = nullptr, const QString *pwd = 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
|
//! Safely replace the expandos in a shell command
|
||||||
static bool expandMacros(QString *cmd, AbstractMacroExpander *mx,
|
static bool expandMacros(
|
||||||
OsType osType = HostOsInfo::hostOs());
|
QString *cmd, const FindMacro &findMacro, OsType osType = HostOsInfo::hostOs());
|
||||||
|
|
||||||
/*! Iterate over arguments from a command line.
|
/*! Iterate over arguments from a command line.
|
||||||
* Assumes that the name of the actual command is *not* part of the line.
|
* Assumes that the name of the actual command is *not* part of the line.
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -27,12 +28,112 @@ const char kNativePathPostfix[] = ":NativePath";
|
|||||||
const char kFileNamePostfix[] = ":FileName";
|
const char kFileNamePostfix[] = ":FileName";
|
||||||
const char kFileBaseNamePostfix[] = ":FileBaseName";
|
const char kFileBaseNamePostfix[] = ":FileBaseName";
|
||||||
|
|
||||||
class MacroExpanderPrivate : public AbstractMacroExpander
|
class MacroExpanderPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MacroExpanderPrivate() = default;
|
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:
|
// Prevent loops:
|
||||||
const int count = seen.count();
|
const int count = seen.count();
|
||||||
@@ -229,7 +330,7 @@ MacroExpander::~MacroExpander()
|
|||||||
*/
|
*/
|
||||||
bool MacroExpander::resolveMacro(const QString &name, QString *ret) const
|
bool MacroExpander::resolveMacro(const QString &name, QString *ret) const
|
||||||
{
|
{
|
||||||
QSet<AbstractMacroExpander*> seen;
|
QSet<MacroExpanderPrivate *> seen;
|
||||||
return d->resolveMacro(name, ret, 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);
|
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.
|
* Returns \a stringWithVariables with all variables replaced by their values.
|
||||||
* See the MacroExpander overview documentation for other ways to expand variables.
|
* 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;
|
++d->m_lockDepth;
|
||||||
|
|
||||||
QString res = stringWithVariables;
|
QString res = stringWithVariables;
|
||||||
Utils::expandMacros(&res, d);
|
expandMacros(&res, d);
|
||||||
|
|
||||||
--d->m_lockDepth;
|
--d->m_lockDepth;
|
||||||
|
|
||||||
@@ -302,10 +413,14 @@ QVariant MacroExpander::expandVariant(const QVariant &v) const
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MacroExpander::expandProcessArgs(const QString &argsWithVariables) const
|
QString MacroExpander::expandProcessArgs(const QString &argsWithVariables, Utils::OsType osType) const
|
||||||
{
|
{
|
||||||
QString result = argsWithVariables;
|
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);
|
QTC_ASSERT(ok, qCDebug(expanderLog) << "Expanding failed: " << argsWithVariables);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "utils_global.h"
|
#include "utils_global.h"
|
||||||
|
|
||||||
|
#include "hostosinfo.h"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -35,7 +37,8 @@ public:
|
|||||||
QByteArray expand(const QByteArray &stringWithVariables) const;
|
QByteArray expand(const QByteArray &stringWithVariables) const;
|
||||||
QVariant expandVariant(const QVariant &v) 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 PrefixFunction = std::function<QString(QString)>;
|
||||||
using ResolverFunction = std::function<bool(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);
|
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)
|
QTCREATOR_UTILS_EXPORT QString stripAccelerator(const QString &text)
|
||||||
{
|
{
|
||||||
QString res = 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.
|
// 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);
|
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 int parseUsedPortFromNetstatOutput(const QByteArray &line);
|
||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT QString appendHelper(const QString &base, int n);
|
QTCREATOR_UTILS_EXPORT QString appendHelper(const QString &base, int n);
|
||||||
|
@@ -173,6 +173,7 @@ private slots:
|
|||||||
{
|
{
|
||||||
QTest::addColumn<QString>("input");
|
QTest::addColumn<QString>("input");
|
||||||
QTest::addColumn<QString>("expected");
|
QTest::addColumn<QString>("expected");
|
||||||
|
QTest::addColumn<OsType>("os");
|
||||||
QTest::addColumn<std::function<void(MacroExpander &)>>("setup");
|
QTest::addColumn<std::function<void(MacroExpander &)>>("setup");
|
||||||
|
|
||||||
std::function<void(MacroExpander &)> empty;
|
std::function<void(MacroExpander &)> empty;
|
||||||
@@ -184,57 +185,63 @@ private slots:
|
|||||||
expander.registerVariable("WithSpace", "", [] { return "This has spaces"; });
|
expander.registerVariable("WithSpace", "", [] { return "This has spaces"; });
|
||||||
};
|
};
|
||||||
|
|
||||||
QTest::newRow("empty") << QString() << QString() << empty;
|
QTest::newRow("empty") << QString() << QString() << Utils::OsTypeLinux << empty;
|
||||||
QTest::newRow("no expansion") << QString("foo") << QString("foo") << empty;
|
QTest::newRow("no expansion")
|
||||||
|
<< QString("foo") << QString("foo") << Utils::OsTypeLinux << empty;
|
||||||
|
|
||||||
QTest::newRow("simple-expansion")
|
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")
|
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\"'")
|
QTest::newRow("with-ticks-env")
|
||||||
<< QString("file=foo.txt echo -n 'foo \"$file\"'") << file;
|
<< 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")
|
QTest::newRow("with-spaces")
|
||||||
<< QString("echo %{WithSpace}") << QString("echo \"This has spaces\"") << withspace;
|
<< 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-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-pre-quoted")
|
QTest::newRow("with-spaces-pre-quoted")
|
||||||
<< QString("echo 'Some: %{WithSpace}'") << QString("echo 'Some: This has spaces'")
|
<< QString("echo 'Some: %{WithSpace}'") << QString("echo 'Some: This has spaces'")
|
||||||
<< withspace;
|
<< Utils::OsTypeLinux << withspace;
|
||||||
|
|
||||||
QTest::newRow("with-spaces-nested")
|
QTest::newRow("with-spaces-nested")
|
||||||
<< QString("sh -c 'echo %{WithSpace}'") << QString("sh -c 'echo This has spaces'")
|
<< QString("sh -c 'echo %{WithSpace}'") << QString("sh -c 'echo This has spaces'")
|
||||||
<< withspace;
|
<< Utils::OsTypeLinux << withspace;
|
||||||
|
|
||||||
// Due to security concerns, backslash-escaping an expando is treated as a quoting error
|
// Due to security concerns, backslash-escaping an expando is treated as a quoting error
|
||||||
QTest::newRow("backslash-escaping")
|
QTest::newRow("backslash-escaping")
|
||||||
<< QString("echo \\%{file}") << QString("echo \\%{file}") << file;
|
<< QString("echo \\%{file}") << QString("echo \\%{file}") << Utils::OsTypeLinux << file;
|
||||||
|
|
||||||
QTest::newRow("expando-within-shell-substitution")
|
QTest::newRow("expando-within-shell-substitution")
|
||||||
<< QString("${VAR:-%{file}}") << QString("${VAR:-foo.txt}") << file;
|
<< QString("${VAR:-%{file}}") << QString("${VAR:-foo.txt}") << Utils::OsTypeLinux
|
||||||
|
<< file;
|
||||||
QTest::newRow("expando-within-shell-substitution-with-space")
|
QTest::newRow("expando-within-shell-substitution-with-space")
|
||||||
<< QString("echo \"Some: ${VAR:-%{WithSpace}}\"")
|
<< QString("echo \"Some: ${VAR:-%{WithSpace}}\"")
|
||||||
<< QString("echo \"Some: ${VAR:-This has spaces}\"") << withspace;
|
<< QString("echo \"Some: ${VAR:-This has spaces}\"") << Utils::OsTypeLinux << withspace;
|
||||||
}
|
|
||||||
|
// Windows tests
|
||||||
|
QTest::newRow("with-spaces")
|
||||||
|
<< QString("echo %{WithSpace}") << QString("echo \"This has spaces\"")
|
||||||
|
<< Utils::OsTypeWindows << 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()
|
void expandCommandArgs()
|
||||||
{
|
{
|
||||||
QFETCH(QString, input);
|
QFETCH(QString, input);
|
||||||
QFETCH(QString, expected);
|
QFETCH(QString, expected);
|
||||||
|
QFETCH(OsType, os);
|
||||||
QFETCH(std::function<void(MacroExpander &)>, setup);
|
QFETCH(std::function<void(MacroExpander &)>, setup);
|
||||||
|
|
||||||
MacroExpander expander;
|
MacroExpander expander;
|
||||||
@@ -242,7 +249,354 @@ private slots:
|
|||||||
if (setup)
|
if (setup)
|
||||||
setup(expander);
|
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;
|
int MessageHandler::s_destroyCount = 0;
|
||||||
QtMessageHandler MessageHandler::s_oldMessageHandler = 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[] =
|
static constexpr char s_skipTerminateOnWindows[] =
|
||||||
"Windows implementation of this test is lacking handling of WM_CLOSE message.";
|
"Windows implementation of this test is lacking handling of WM_CLOSE message.";
|
||||||
|
|
||||||
@@ -135,8 +112,6 @@ private slots:
|
|||||||
void prepareArgs();
|
void prepareArgs();
|
||||||
void prepareArgsEnv_data();
|
void prepareArgsEnv_data();
|
||||||
void prepareArgsEnv();
|
void prepareArgsEnv();
|
||||||
void expandMacros_data();
|
|
||||||
void expandMacros();
|
|
||||||
void iterations_data();
|
void iterations_data();
|
||||||
void iterations();
|
void iterations();
|
||||||
void iteratorEditsWindows();
|
void iteratorEditsWindows();
|
||||||
@@ -181,8 +156,6 @@ private:
|
|||||||
Environment envWindows;
|
Environment envWindows;
|
||||||
Environment envLinux;
|
Environment envLinux;
|
||||||
|
|
||||||
MacroMapExpander mxWin;
|
|
||||||
MacroMapExpander mxUnix;
|
|
||||||
QString homeStr;
|
QString homeStr;
|
||||||
QString home;
|
QString home;
|
||||||
|
|
||||||
@@ -206,38 +179,6 @@ void tst_Process::initTestCase()
|
|||||||
env << "empty=" << "word=hi" << "words=hi ho" << "spacedwords= hi ho sucker ";
|
env << "empty=" << "word=hi" << "words=hi ho" << "spacedwords= hi ho sucker ";
|
||||||
envWindows = Environment(env, OsTypeWindows);
|
envWindows = Environment(env, OsTypeWindows);
|
||||||
envLinux = Environment(env, OsTypeLinux);
|
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()
|
void tst_Process::cleanupTestCase()
|
||||||
@@ -550,252 +491,7 @@ void tst_Process::prepareArgsEnv()
|
|||||||
QCOMPARE(outstr, out);
|
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()
|
void tst_Process::iterations_data()
|
||||||
{
|
{
|
||||||
|
@@ -10,66 +10,12 @@
|
|||||||
|
|
||||||
using namespace Utils;
|
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
|
class tst_StringUtils : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void testWithTildeHomePath();
|
void testWithTildeHomePath();
|
||||||
void testMacroExpander_data();
|
|
||||||
void testMacroExpander();
|
|
||||||
void testStripAccelerator_data();
|
void testStripAccelerator_data();
|
||||||
void testStripAccelerator();
|
void testStripAccelerator();
|
||||||
void testParseUsedPortFromNetstatOutput_data();
|
void testParseUsedPortFromNetstatOutput_data();
|
||||||
@@ -84,9 +30,6 @@ private slots:
|
|||||||
void testSplitAtFirst();
|
void testSplitAtFirst();
|
||||||
void testAsciify_data();
|
void testAsciify_data();
|
||||||
void testAsciify();
|
void testAsciify();
|
||||||
|
|
||||||
private:
|
|
||||||
TestMacroExpander mx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_StringUtils::testWithTildeHomePath()
|
void tst_StringUtils::testWithTildeHomePath()
|
||||||
@@ -118,68 +61,6 @@ void tst_StringUtils::testWithTildeHomePath()
|
|||||||
#endif
|
#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()
|
void tst_StringUtils::testStripAccelerator_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("expected");
|
QTest::addColumn<QString>("expected");
|
||||||
|
Reference in New Issue
Block a user