Commit 721df6f1 authored by Elvis Angelaccio's avatar Elvis Angelaccio

cliinterface: refactor the replacement of AddArgs

with unit tests for clirar and cli7z.

Differential Revision: D1265
parent 482e7718
......@@ -224,6 +224,63 @@ void Cli7zTest::testListArgs()
plugin->deleteLater();
}
void Cli7zTest::testAddArgs_data()
{
QTest::addColumn<QString>("archiveName");
QTest::addColumn<QString>("password");
QTest::addColumn<bool>("encryptHeader");
QTest::addColumn<QStringList>("expectedArgs");
QTest::newRow("unencrypted")
<< QStringLiteral("/tmp/foo.7z")
<< QString() << false
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.7z")
};
QTest::newRow("encrypted")
<< QStringLiteral("/tmp/foo.7z")
<< QStringLiteral("1234") << false
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.7z"),
QStringLiteral("-p1234")
};
QTest::newRow("header-encrypted")
<< QStringLiteral("/tmp/foo.7z")
<< QStringLiteral("1234") << true
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.7z"),
QStringLiteral("-p1234"),
QStringLiteral("-mhe=on")
};
}
void Cli7zTest::testAddArgs()
{
QFETCH(QString, archiveName);
CliPlugin *plugin = new CliPlugin(this, {QVariant(archiveName)});
QVERIFY(plugin);
const QStringList addArgs = { QStringLiteral("a"),
QStringLiteral("$Archive"),
QStringLiteral("$PasswordSwitch"),
QStringLiteral("$Files") };
QFETCH(QString, password);
QFETCH(bool, encryptHeader);
QStringList replacedArgs = plugin->substituteAddVariables(addArgs, {}, QDir::current(), password, encryptHeader);
QFETCH(QStringList, expectedArgs);
QCOMPARE(replacedArgs, expectedArgs);
plugin->deleteLater();
}
void Cli7zTest::testExtractArgs_data()
{
QTest::addColumn<QString>("archiveName");
......
......@@ -43,6 +43,8 @@ private Q_SLOTS:
void testList();
void testListArgs_data();
void testListArgs();
void testAddArgs_data();
void testAddArgs();
void testExtractArgs_data();
void testExtractArgs();
......
......@@ -258,6 +258,62 @@ void CliRarTest::testListArgs()
plugin->deleteLater();
}
void CliRarTest::testAddArgs_data()
{
QTest::addColumn<QString>("archiveName");
QTest::addColumn<QString>("password");
QTest::addColumn<bool>("encryptHeader");
QTest::addColumn<QStringList>("expectedArgs");
QTest::newRow("unencrypted")
<< QStringLiteral("/tmp/foo.rar")
<< QString() << false
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.rar")
};
QTest::newRow("encrypted")
<< QStringLiteral("/tmp/foo.rar")
<< QStringLiteral("1234") << false
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.rar"),
QStringLiteral("-p1234")
};
QTest::newRow("header-encrypted")
<< QStringLiteral("/tmp/foo.rar")
<< QStringLiteral("1234") << true
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.rar"),
QStringLiteral("-hp1234")
};
}
void CliRarTest::testAddArgs()
{
QFETCH(QString, archiveName);
CliPlugin *rarPlugin = new CliPlugin(this, {QVariant(archiveName)});
QVERIFY(rarPlugin);
const QStringList addArgs = { QStringLiteral("a"),
QStringLiteral("$Archive"),
QStringLiteral("$PasswordSwitch"),
QStringLiteral("$Files") };
QFETCH(QString, password);
QFETCH(bool, encryptHeader);
QStringList replacedArgs = rarPlugin->substituteAddVariables(addArgs, {}, QDir::current(), password, encryptHeader);
QFETCH(QStringList, expectedArgs);
QCOMPARE(replacedArgs, expectedArgs);
rarPlugin->deleteLater();
}
void CliRarTest::testExtractArgs_data()
{
QTest::addColumn<QString>("archiveName");
......
......@@ -44,6 +44,8 @@ private Q_SLOTS:
void testList();
void testListArgs_data();
void testListArgs();
void testAddArgs_data();
void testAddArgs();
void testExtractArgs_data();
void testExtractArgs();
......
......@@ -252,93 +252,11 @@ bool CliInterface::addFiles(const QStringList & files, const CompressionOptions&
QDir::setCurrent(globalWorkDir);
}
//start preparing the argument list
QStringList args = m_param.value(AddArgs).toStringList();
//now replace the various elements in the list
for (int i = 0; i < args.size(); ++i) {
const QString argument = args.at(i);
qCDebug(ARK) << "Processing argument " << argument;
if (argument == QLatin1String( "$Archive" )) {
args[i] = filename();
}
if (argument == QLatin1String("$PasswordSwitch")) {
//if the PasswordSwitch argument has been added, we at least
//assume that the format of the switch has been added as well
Q_ASSERT(m_param.contains(PasswordSwitch));
//we will decrement i afterwards
args.removeAt(i);
QString pass = password();
if (!pass.isEmpty()) {
QStringList theSwitch = m_param.value(PasswordSwitch).toStringList();
// use the header encryption switch if needed and if provided by the plugin
if (isHeaderEncryptionEnabled() && !m_param.value(PasswordHeaderSwitch).toStringList().isEmpty()) {
theSwitch = m_param.value(PasswordHeaderSwitch).toStringList();
}
for (int j = 0; j < theSwitch.size(); ++j) {
//get the argument part
QString newArg = theSwitch.at(j);
//substitute the $Password
newArg.replace(QLatin1String("$Password"), pass);
//put it in the arg list
args.insert(i + j, newArg);
++i;
}
}
--i; //decrement to compensate for the variable we replaced
}
if (argument == QLatin1String("$EncryptHeaderSwitch")) {
//if the EncryptHeaderSwitch argument has been added, we at least
//assume that the format of the switch has been added as well
Q_ASSERT(m_param.contains(EncryptHeaderSwitch));
//we will decrement i afterwards
args.removeAt(i);
QString enabled = isHeaderEncryptionEnabled() ? QStringLiteral("-mhe=on") : QString();
QStringList theSwitch = m_param.value(EncryptHeaderSwitch).toStringList();
for (int j = 0; j < theSwitch.size(); ++j) {
//get the argument part
QString newArg = theSwitch.at(j);
//substitute the $Password
newArg.replace(QLatin1String("$Enabled"), enabled);
//put it in the arg list
args.insert(i + j, newArg);
++i;
}
--i; //decrement to compensate for the variable we replaced
}
if (argument == QLatin1String( "$Files" )) {
args.removeAt(i);
for (int j = 0; j < files.count(); ++j) {
// #191821: workDir must be used instead of QDir::current()
// so that symlinks aren't resolved automatically
// TODO: this kind of call should be moved upwards in the
// class hierarchy to avoid code duplication
const QString relativeName =
workDir.relativeFilePath(files.at(j));
args.insert(i + j, relativeName);
++i;
}
--i;
}
}
const auto args = substituteAddVariables(m_param.value(AddArgs).toStringList(),
files,
workDir,
password(),
isHeaderEncryptionEnabled());
if (!runProcess(m_param.value(AddProgram).toStringList(), args)) {
failOperation();
......@@ -709,6 +627,40 @@ QStringList CliInterface::substituteCopyVariables(const QStringList &extractArgs
return args;
}
QStringList CliInterface::substituteAddVariables(const QStringList &addArgs, const QStringList &files, const QDir &workDir, const QString &password, bool encryptHeader)
{
// Required if we call this function from unit tests.
cacheParameterList();
QStringList args;
foreach (const QString& arg, addArgs) {
qCDebug(ARK) << "Processing argument " << arg;
if (arg == QLatin1String("$Archive")) {
args << filename();
continue;
}
if (arg == QLatin1String("$PasswordSwitch")) {
args << (encryptHeader ? passwordHeaderSwitch(password) : passwordSwitch(password));
continue;
}
if (arg == QLatin1String("$Files")) {
args << addFilesList(files, workDir);
continue;
}
// Simple argument (e.g. a in 7z), nothing to substitute, just add it to the list.
args << arg;
}
// Remove empty strings, if any.
args.removeAll(QString());
return args;
}
QString CliInterface::preservePathSwitch(bool preservePaths) const
{
Q_ASSERT(m_param.contains(PreservePathSwitch));
......@@ -718,6 +670,26 @@ QString CliInterface::preservePathSwitch(bool preservePaths) const
return (preservePaths ? theSwitch.at(0) : theSwitch.at(1));
}
QStringList CliInterface::passwordHeaderSwitch(const QString& password) const
{
if (password.isEmpty()) {
return QStringList();
}
Q_ASSERT(m_param.contains(PasswordHeaderSwitch));
QStringList passwordHeaderSwitch = m_param.value(PasswordHeaderSwitch).toStringList();
Q_ASSERT(!passwordHeaderSwitch.isEmpty() && passwordHeaderSwitch.size() <= 2);
if (passwordHeaderSwitch.size() == 1) {
passwordHeaderSwitch[0].replace(QLatin1String("$Password"), password);
} else {
passwordHeaderSwitch[1] = password;
}
return passwordHeaderSwitch;
}
QStringList CliInterface::passwordSwitch(const QString& password) const
{
if (password.isEmpty()) {
......@@ -758,6 +730,21 @@ QStringList CliInterface::rootNodeSwitch(const QString &rootNode) const
return rootNodeSwitch;
}
QStringList CliInterface::addFilesList(const QStringList& files, const QDir& workDir) const
{
// #191821: workDir must be used instead of QDir::current()
// so that symlinks aren't resolved automatically
// TODO: this kind of call should be moved upwards in the
// class hierarchy to avoid code duplication
QStringList filesList;
foreach (const QString& file, files) {
filesList << workDir.relativeFilePath(file);
}
return filesList;
}
QStringList CliInterface::copyFilesList(const QVariantList& files) const
{
QStringList filesList;
......
......@@ -246,16 +246,6 @@ enum CliInterfaceParameters {
* Example (rar plugin): ("-hp$Password")
*/
PasswordHeaderSwitch,
/**
* QStringList (default empty)
* Encrypt the archive header without providing a password string.
* It uses $Password from either PasswordSwitch or PasswordHeaderSwitch.
* However, there is the $Enabled variable
* which is substituted with either 'on' or 'off'.
* Example (7z plugin): ("-mhe=$Enabled")
*/
EncryptHeaderSwitch
};
typedef QHash<int, QVariant> ParameterList;
......@@ -319,12 +309,18 @@ public:
QStringList substituteListVariables(const QStringList &listArgs, const QString &password);
QStringList substituteCopyVariables(const QStringList &extractArgs, const QVariantList &files, bool preservePaths, const QString &password, const QString &rootNode);
QStringList substituteAddVariables(const QStringList &addArgs, const QStringList &files, const QDir &workDir, const QString &password, bool encryptHeader);
/**
* @return The preserve path switch, according to the @p preservePaths extraction option.
*/
QString preservePathSwitch(bool preservePaths) const;
/**
* @return The password header-switch with the given @p password.
*/
virtual QStringList passwordHeaderSwitch(const QString& password) const;
/**
* @return The password switch with the given @p password.
*/
......@@ -335,6 +331,11 @@ public:
*/
QStringList rootNodeSwitch(const QString& rootNode) const;
/**
* @return The list of files to add to the archive.
*/
QStringList addFilesList(const QStringList& files, const QDir& workDir) const;
/**
* @return The list of selected files to extract.
*/
......
......@@ -72,11 +72,10 @@ ParameterList CliPlugin::parameterList() const
p[PreservePathSwitch] = QStringList() << QStringLiteral("x")
<< QStringLiteral("e");
p[PasswordSwitch] = QStringList() << QStringLiteral("-p$Password");
p[EncryptHeaderSwitch] = QStringList() << QStringLiteral("$Enabled");
p[PasswordHeaderSwitch] = QStringList { QStringLiteral("-p$Password"), QStringLiteral("-mhe=on") };
p[WrongPasswordPatterns] = QStringList() << QStringLiteral("Wrong password");
p[AddArgs] = QStringList() << QStringLiteral("a")
<< QStringLiteral("$Archive")
<< QStringLiteral("$EncryptHeaderSwitch")
<< QStringLiteral("$PasswordSwitch")
<< QStringLiteral("$Files");
p[DeleteArgs] = QStringList() << QStringLiteral("d")
......@@ -234,4 +233,20 @@ bool CliPlugin::readListLine(const QString& line)
return true;
}
QStringList CliPlugin::passwordHeaderSwitch(const QString& password) const
{
if (password.isEmpty()) {
return QStringList();
}
Q_ASSERT(m_param.contains(PasswordHeaderSwitch));
QStringList passwordHeaderSwitch = m_param.value(PasswordHeaderSwitch).toStringList();
Q_ASSERT(!passwordHeaderSwitch.isEmpty() && passwordHeaderSwitch.size() == 2);
passwordHeaderSwitch[0].replace(QLatin1String("$Password"), password);
return passwordHeaderSwitch;
}
#include "cliplugin.moc"
......@@ -38,6 +38,11 @@ public:
virtual Kerfuffle::ParameterList parameterList() const Q_DECL_OVERRIDE;
virtual bool readListLine(const QString &line) Q_DECL_OVERRIDE;
/**
* @return The password header-switch with the given @p password.
*/
virtual QStringList passwordHeaderSwitch(const QString& password) const Q_DECL_OVERRIDE;
private:
enum ArchiveType {
ArchiveType7z = 0,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment