File indexing completed on 2024-06-16 05:20:38

0001 /*
0002     SPDX-FileCopyrightText: 2016 Elvis Angelaccio <elvis.angelaccio@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "cliunarchivertest.h"
0008 #include "jobs.h"
0009 #include "testhelper.h"
0010 
0011 #include <QDirIterator>
0012 #include <QFile>
0013 #include <QSignalSpy>
0014 #include <QTest>
0015 #include <QTextStream>
0016 
0017 QTEST_GUILESS_MAIN(CliUnarchiverTest)
0018 
0019 using namespace Kerfuffle;
0020 
0021 void CliUnarchiverTest::initTestCase()
0022 {
0023     m_plugin = new Plugin(this);
0024     const auto plugins = m_pluginManger.availablePlugins();
0025     for (Plugin *plugin : plugins) {
0026         if (plugin->metaData().pluginId() == QLatin1String("kerfuffle_cliunarchiver")) {
0027             m_plugin = plugin;
0028             return;
0029         }
0030     }
0031 }
0032 
0033 void CliUnarchiverTest::testArchive_data()
0034 {
0035     QTest::addColumn<QString>("archivePath");
0036     QTest::addColumn<QString>("expectedFileName");
0037     QTest::addColumn<bool>("isReadOnly");
0038     QTest::addColumn<bool>("isSingleFolder");
0039     QTest::addColumn<Archive::EncryptionType>("expectedEncryptionType");
0040     QTest::addColumn<QString>("expectedSubfolderName");
0041 
0042     QString archivePath = QFINDTESTDATA("data/one_toplevel_folder.rar");
0043     QTest::newRow("RAR archive with one top-level folder")
0044         << archivePath << QFileInfo(archivePath).fileName() << true << true << Archive::Unencrypted << QStringLiteral("A");
0045 
0046     archivePath = QFINDTESTDATA("data/multiple_toplevel_entries.rar");
0047     QTest::newRow("RAR archive with multiple top-level entries")
0048         << archivePath << QFileInfo(archivePath).fileName() << true << false << Archive::Unencrypted << QStringLiteral("multiple_toplevel_entries");
0049 
0050     archivePath = QFINDTESTDATA("data/encrypted_entries.rar");
0051     QTest::newRow("RAR archive with encrypted entries")
0052         << archivePath << QFileInfo(archivePath).fileName() << true << true << Archive::Encrypted << QStringLiteral("A");
0053 
0054     archivePath = QFINDTESTDATA("data/one_toplevel_folder.lha");
0055     QTest::newRow("LHA archive with one top-level folder")
0056         << archivePath << QFileInfo(archivePath).fileName() << true << true << Archive::Unencrypted << QStringLiteral("A");
0057 
0058     archivePath = QFINDTESTDATA("data/multiple_toplevel_entries.lha");
0059     QTest::newRow("LHA archive with multiple top-level entries")
0060         << archivePath << QFileInfo(archivePath).fileName() << true << false << Archive::Unencrypted << QStringLiteral("multiple_toplevel_entries");
0061 
0062     archivePath = QFINDTESTDATA("data/test.sit");
0063     QTest::newRow("stuffit archive unencrypted") << archivePath << QFileInfo(archivePath).fileName() << true << false << Archive::Unencrypted
0064                                                  << QStringLiteral("test");
0065 }
0066 
0067 void CliUnarchiverTest::testArchive()
0068 {
0069     if (!m_plugin->isValid()) {
0070         QSKIP("cliunarchiver plugin not available. Skipping test.", SkipSingle);
0071     }
0072 
0073     QFETCH(QString, archivePath);
0074     auto loadJob = Archive::load(archivePath, m_plugin, this);
0075     QVERIFY(loadJob);
0076 
0077     TestHelper::startAndWaitForResult(loadJob);
0078     auto archive = loadJob->archive();
0079     QVERIFY(archive);
0080 
0081     if (!archive->isValid()) {
0082         QSKIP("Could not load the cliunarchiver plugin. Skipping test.", SkipSingle);
0083     }
0084 
0085     QFETCH(QString, expectedFileName);
0086     QCOMPARE(QFileInfo(archive->fileName()).fileName(), expectedFileName);
0087 
0088     QFETCH(bool, isReadOnly);
0089     QCOMPARE(archive->isReadOnly(), isReadOnly);
0090 
0091     QFETCH(bool, isSingleFolder);
0092     QCOMPARE(archive->isSingleFolder(), isSingleFolder);
0093 
0094     QFETCH(Archive::EncryptionType, expectedEncryptionType);
0095     QCOMPARE(archive->encryptionType(), expectedEncryptionType);
0096 
0097     QFETCH(QString, expectedSubfolderName);
0098     QCOMPARE(archive->subfolderName(), expectedSubfolderName);
0099 }
0100 
0101 void CliUnarchiverTest::testList_data()
0102 {
0103     QTest::addColumn<QString>("jsonFilePath");
0104     QTest::addColumn<int>("expectedEntriesCount");
0105     // Index of some entry to be tested.
0106     QTest::addColumn<int>("someEntryIndex");
0107     // Entry metadata.
0108     QTest::addColumn<QString>("expectedName");
0109     QTest::addColumn<bool>("isDirectory");
0110     QTest::addColumn<bool>("isPasswordProtected");
0111     QTest::addColumn<qulonglong>("expectedSize");
0112     QTest::addColumn<qulonglong>("expectedCompressedSize");
0113     QTest::addColumn<QString>("expectedTimestamp");
0114 
0115     QTest::newRow("archive with one top-level folder") << QFINDTESTDATA("data/one_toplevel_folder.json") << 9 << 6 << QStringLiteral("A/B/C/") << true << false
0116                                                        << (qulonglong)0 << (qulonglong)0 << QStringLiteral("2015-12-21T16:57:20+01:00");
0117     QTest::newRow("archive with multiple top-level entries")
0118         << QFINDTESTDATA("data/multiple_toplevel_entries.json") << 12 << 4 << QStringLiteral("data/A/B/test1.txt") << false << false << (qulonglong)7
0119         << (qulonglong)7 << QStringLiteral("2015-12-21T16:56:28+01:00");
0120     QTest::newRow("archive with encrypted entries") << QFINDTESTDATA("data/encrypted_entries.json") << 9 << 5 << QStringLiteral("A/test1.txt") << false << true
0121                                                     << (qulonglong)7 << (qulonglong)32 << QStringLiteral("2015-12-21T16:56:28+01:00");
0122     QTest::newRow("huge archive") << QFINDTESTDATA("data/huge_archive.json") << 250 << 8 << QStringLiteral("PsycOPacK/Base Dictionnaries/att800") << false
0123                                   << false << (qulonglong)593687 << (qulonglong)225219 << QStringLiteral("2011-08-14T03:10:10+02:00");
0124 }
0125 
0126 void CliUnarchiverTest::testList()
0127 {
0128     qRegisterMetaType<Archive::Entry *>("Archive::Entry*");
0129     CliPlugin *plugin = new CliPlugin(this, {QStringLiteral("dummy.rar"), QVariant::fromValue(m_plugin->metaData())});
0130     QSignalSpy signalSpy(plugin, &CliPlugin::entry);
0131 
0132     QFETCH(QString, jsonFilePath);
0133     QFETCH(int, expectedEntriesCount);
0134 
0135     QFile jsonFile(jsonFilePath);
0136     QVERIFY(jsonFile.open(QIODevice::ReadOnly));
0137 
0138     QTextStream stream(&jsonFile);
0139     plugin->setJsonOutput(stream.readAll());
0140 
0141     QCOMPARE(signalSpy.count(), expectedEntriesCount);
0142 
0143     QFETCH(int, someEntryIndex);
0144     QVERIFY(someEntryIndex < signalSpy.count());
0145     Archive::Entry *entry = signalSpy.at(someEntryIndex).at(0).value<Archive::Entry *>();
0146 
0147     QFETCH(QString, expectedName);
0148     QCOMPARE(entry->fullPath(), expectedName);
0149 
0150     QFETCH(bool, isDirectory);
0151     QCOMPARE(entry->isDir(), isDirectory);
0152 
0153     QFETCH(bool, isPasswordProtected);
0154     QCOMPARE(entry->property("isPasswordProtected").toBool(), isPasswordProtected);
0155 
0156     QFETCH(qulonglong, expectedSize);
0157     QCOMPARE(entry->property("size").toULongLong(), expectedSize);
0158 
0159     QFETCH(qulonglong, expectedCompressedSize);
0160     QCOMPARE(entry->property("compressedSize").toULongLong(), expectedCompressedSize);
0161 
0162     QFETCH(QString, expectedTimestamp);
0163     QEXPECT_FAIL("", "Something changed since Qt 5.11, needs investigation.", Continue);
0164     QCOMPARE(entry->property("timestamp").toString(), expectedTimestamp);
0165 
0166     plugin->deleteLater();
0167 }
0168 
0169 void CliUnarchiverTest::testListArgs_data()
0170 {
0171     QTest::addColumn<QString>("archiveName");
0172     QTest::addColumn<QString>("password");
0173     QTest::addColumn<QStringList>("expectedArgs");
0174 
0175     QTest::newRow("unencrypted") << QStringLiteral("/tmp/foo.rar") << QString() << QStringList{QStringLiteral("-json"), QStringLiteral("/tmp/foo.rar")};
0176 
0177     QTest::newRow("header-encrypted") << QStringLiteral("/tmp/foo.rar") << QStringLiteral("1234")
0178                                       << QStringList{QStringLiteral("-json"),
0179                                                      QStringLiteral("-password"),
0180                                                      QStringLiteral("1234"),
0181                                                      QStringLiteral("/tmp/foo.rar")};
0182 }
0183 
0184 void CliUnarchiverTest::testListArgs()
0185 {
0186     if (!m_plugin->isValid()) {
0187         QSKIP("cliunarchiver plugin not available. Skipping test.", SkipSingle);
0188     }
0189 
0190     QFETCH(QString, archiveName);
0191     CliPlugin *plugin = new CliPlugin(this, {QVariant(archiveName), QVariant::fromValue(m_plugin->metaData())});
0192     QVERIFY(plugin);
0193 
0194     QFETCH(QString, password);
0195     const auto replacedArgs = plugin->cliProperties()->listArgs(archiveName, password);
0196 
0197     QFETCH(QStringList, expectedArgs);
0198     QCOMPARE(replacedArgs, expectedArgs);
0199 
0200     plugin->deleteLater();
0201 }
0202 
0203 void CliUnarchiverTest::testExtraction_data()
0204 {
0205     QTest::addColumn<QString>("archivePath");
0206     QTest::addColumn<QVector<Archive::Entry *>>("entriesToExtract");
0207     QTest::addColumn<ExtractionOptions>("extractionOptions");
0208     QTest::addColumn<int>("expectedExtractedEntriesCount");
0209 
0210     ExtractionOptions defaultOptions;
0211     defaultOptions.setAlwaysUseTempDir(true);
0212 
0213     ExtractionOptions optionsNoPaths = defaultOptions;
0214     optionsNoPaths.setPreservePaths(false);
0215 
0216     ExtractionOptions dragAndDropOptions = defaultOptions;
0217     dragAndDropOptions.setDragAndDropEnabled(true);
0218 
0219     QTest::newRow("extract the whole multiple_toplevel_entries.rar")
0220         << QFINDTESTDATA("data/multiple_toplevel_entries.rar") << QVector<Archive::Entry *>() << defaultOptions << 12;
0221 
0222     QTest::newRow("extract selected entries from a rar, without paths")
0223         << QFINDTESTDATA("data/one_toplevel_folder.rar")
0224         << QVector<Archive::Entry *>{new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A")),
0225                                      new Archive::Entry(this, QStringLiteral("A/B/test1.txt"), QStringLiteral("A/B"))}
0226         << optionsNoPaths << 2;
0227 
0228     QTest::newRow("extract selected entries from a rar, preserve paths")
0229         << QFINDTESTDATA("data/one_toplevel_folder.rar")
0230         << (QVector<Archive::Entry *>{
0231                new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A")),
0232                new Archive::Entry(this, QStringLiteral("A/B/test1.txt"), QStringLiteral("A/B")),
0233            })
0234         << defaultOptions << 4;
0235 
0236     QTest::newRow("extract selected entries from a rar, drag-and-drop")
0237         << QFINDTESTDATA("data/one_toplevel_folder.rar")
0238         << (QVector<Archive::Entry *>{
0239                new Archive::Entry(this, QStringLiteral("A/B/C/"), QStringLiteral("A/B/")),
0240                new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A/")),
0241                new Archive::Entry(this, QStringLiteral("A/B/C/test1.txt"), QStringLiteral("A/B/")),
0242                new Archive::Entry(this, QStringLiteral("A/B/C/test2.txt"), QStringLiteral("A/B/")),
0243            })
0244         << dragAndDropOptions << 4;
0245 
0246     QTest::newRow("rar with empty folders") << QFINDTESTDATA("data/empty_folders.rar") << QVector<Archive::Entry *>() << defaultOptions << 5;
0247 
0248     QTest::newRow("rar with hidden folder and files") << QFINDTESTDATA("data/hidden_files.rar") << QVector<Archive::Entry *>() << defaultOptions << 4;
0249 }
0250 
0251 // TODO: we can remove this test (which is duplicated from kerfuffle/archivetest)
0252 // if we ever ends up using a temp dir for any cliplugin, instead of only for cliunarchiver.
0253 void CliUnarchiverTest::testExtraction()
0254 {
0255     if (!m_plugin->isValid()) {
0256         QSKIP("cliunarchiver plugin not available. Skipping test.", SkipSingle);
0257     }
0258 
0259     QFETCH(QString, archivePath);
0260     auto loadJob = Archive::load(archivePath, m_plugin, this);
0261     QVERIFY(loadJob);
0262 
0263     TestHelper::startAndWaitForResult(loadJob);
0264     auto archive = loadJob->archive();
0265     QVERIFY(archive);
0266 
0267     if (!archive->isValid()) {
0268         QSKIP("Could not load the cliunarchiver plugin. Skipping test.", SkipSingle);
0269     }
0270 
0271     QTemporaryDir destDir;
0272     if (!destDir.isValid()) {
0273         QSKIP("Could not create a temporary directory for extraction. Skipping test.", SkipSingle);
0274     }
0275 
0276     QFETCH(QVector<Archive::Entry *>, entriesToExtract);
0277     QFETCH(ExtractionOptions, extractionOptions);
0278     auto extractionJob = archive->extractFiles(entriesToExtract, destDir.path(), extractionOptions);
0279 
0280     QEventLoop eventLoop(this);
0281     connect(extractionJob, &KJob::result, &eventLoop, &QEventLoop::quit);
0282     extractionJob->start();
0283     eventLoop.exec(); // krazy:exclude=crashy
0284 
0285     QFETCH(int, expectedExtractedEntriesCount);
0286     int extractedEntriesCount = 0;
0287 
0288     QDirIterator dirIt(destDir.path(), QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
0289     while (dirIt.hasNext()) {
0290         extractedEntriesCount++;
0291         dirIt.next();
0292     }
0293 
0294     QCOMPARE(extractedEntriesCount, expectedExtractedEntriesCount);
0295 
0296     archive->deleteLater();
0297 }
0298 
0299 void CliUnarchiverTest::testExtractArgs_data()
0300 {
0301     QTest::addColumn<QString>("archiveName");
0302     QTest::addColumn<QVector<Archive::Entry *>>("files");
0303     QTest::addColumn<QString>("password");
0304     QTest::addColumn<QStringList>("expectedArgs");
0305 
0306     QTest::newRow("encrypted, multiple files") << QStringLiteral("/tmp/foo.rar")
0307                                                << QVector<Archive::Entry *>{new Archive::Entry(this, QStringLiteral("aDir/b.txt"), QStringLiteral("aDir")),
0308                                                                             new Archive::Entry(this, QStringLiteral("c.txt"), QString())}
0309                                                << QStringLiteral("1234")
0310                                                << QStringList{
0311                                                       QStringLiteral("-D"),
0312                                                       QStringLiteral("-password"),
0313                                                       QStringLiteral("1234"),
0314                                                       QStringLiteral("/tmp/foo.rar"),
0315                                                       QStringLiteral("aDir/b.txt"),
0316                                                       QStringLiteral("c.txt"),
0317                                                   };
0318 
0319     QTest::newRow("unencrypted, multiple files") << QStringLiteral("/tmp/foo.rar")
0320                                                  << QVector<Archive::Entry *>{new Archive::Entry(this, QStringLiteral("aDir/b.txt"), QStringLiteral("aDir")),
0321                                                                               new Archive::Entry(this, QStringLiteral("c.txt"), QString())}
0322                                                  << QString()
0323                                                  << QStringList{
0324                                                         QStringLiteral("-D"),
0325                                                         QStringLiteral("/tmp/foo.rar"),
0326                                                         QStringLiteral("aDir/b.txt"),
0327                                                         QStringLiteral("c.txt"),
0328                                                     };
0329 }
0330 
0331 void CliUnarchiverTest::testExtractArgs()
0332 {
0333     if (!m_plugin->isValid()) {
0334         QSKIP("cliunarchiver plugin not available. Skipping test.", SkipSingle);
0335     }
0336 
0337     QFETCH(QString, archiveName);
0338     CliPlugin *plugin = new CliPlugin(this, {QVariant(archiveName), QVariant::fromValue(m_plugin->metaData())});
0339     QVERIFY(plugin);
0340 
0341     QFETCH(QVector<Archive::Entry *>, files);
0342     QStringList filesList;
0343     for (const Archive::Entry *e : std::as_const(files)) {
0344         filesList << e->fullPath(NoTrailingSlash);
0345     }
0346 
0347     QFETCH(QString, password);
0348 
0349     const auto replacedArgs = plugin->cliProperties()->extractArgs(archiveName, filesList, false, password);
0350 
0351     QFETCH(QStringList, expectedArgs);
0352     QCOMPARE(replacedArgs, expectedArgs);
0353 
0354     plugin->deleteLater();
0355 }
0356 
0357 #include "moc_cliunarchivertest.cpp"