File indexing completed on 2024-05-12 05:50:10

0001 /*
0002     SPDX-FileCopyrightText: 2010-2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
0003     SPDX-FileCopyrightText: 2016 Elvis Angelaccio <elvis.angelaccio@kde.org>
0004 
0005     SPDX-License-Identifier: BSD-2-Clause
0006 */
0007 
0008 #include "archive_kerfuffle.h"
0009 #include "jobs.h"
0010 #include "pluginmanager.h"
0011 #include "testhelper.h"
0012 
0013 #include <KIO/Global>
0014 
0015 #include <QDirIterator>
0016 #include <QMimeDatabase>
0017 #include <QStandardPaths>
0018 #include <QTest>
0019 
0020 using namespace Kerfuffle;
0021 
0022 class ExtractTest : public QObject
0023 {
0024     Q_OBJECT
0025 
0026 private Q_SLOTS:
0027     void initTestCase();
0028     void testExtraction_data();
0029     void testExtraction();
0030     void testPreservePermissions_data();
0031     void testPreservePermissions();
0032 
0033 private:
0034     PluginManager m_pluginManager;
0035     QString m_expectedWorkingDir;
0036 };
0037 
0038 QTEST_GUILESS_MAIN(ExtractTest)
0039 
0040 void ExtractTest::initTestCase()
0041 {
0042     // #395939: after each extraction, the cwd must be the one we started from.
0043     m_expectedWorkingDir = QDir::currentPath();
0044 }
0045 
0046 void ExtractTest::testExtraction_data()
0047 {
0048     QTest::addColumn<QString>("archivePath");
0049     QTest::addColumn<QVector<Archive::Entry *>>("entriesToExtract");
0050     QTest::addColumn<ExtractionOptions>("extractionOptions");
0051     QTest::addColumn<int>("expectedExtractedEntriesCount");
0052 
0053     const auto setupRow = [](const char *name,
0054                              const QString &archivePath,
0055                              QVector<Archive::Entry *> entriesToExtract,
0056                              ExtractionOptions extractionOptions,
0057                              int expectedExtractedEntriesCount) {
0058         QTest::newRow(name) << archivePath << entriesToExtract << extractionOptions << expectedExtractedEntriesCount;
0059     };
0060 
0061     ExtractionOptions optionsPreservePaths;
0062 
0063     ExtractionOptions optionsNoPaths;
0064     optionsNoPaths.setPreservePaths(false);
0065 
0066     ExtractionOptions dragAndDropOptions;
0067     dragAndDropOptions.setDragAndDropEnabled(true);
0068 
0069     QString archivePath = QFINDTESTDATA("data/simplearchive.tar.gz");
0070     setupRow("extract the whole simplearchive.tar.gz", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 4);
0071 
0072     archivePath = QFINDTESTDATA("data/simplearchive.tar.gz");
0073     setupRow("extract selected entries from a tar.gz, without paths",
0074              archivePath,
0075              QVector<Archive::Entry *>{
0076                  new Archive::Entry(this, QStringLiteral("aDir/b.txt"), QStringLiteral("aDir")),
0077                  new Archive::Entry(this, QStringLiteral("c.txt"), QString()),
0078              },
0079              optionsNoPaths,
0080              2);
0081 
0082     archivePath = QFINDTESTDATA("data/simplearchive.tar.gz");
0083     setupRow("extract selected entries from a tar.gz, preserve paths",
0084              archivePath,
0085              QVector<Archive::Entry *>{
0086                  new Archive::Entry(this, QStringLiteral("aDir/b.txt"), QStringLiteral("aDir")),
0087                  new Archive::Entry(this, QStringLiteral("c.txt"), QString()),
0088              },
0089              optionsPreservePaths,
0090              3);
0091 
0092     archivePath = QFINDTESTDATA("data/simplearchive.tar.gz");
0093     setupRow("extract selected entries from a tar.gz, drag-and-drop",
0094              archivePath,
0095              QVector<Archive::Entry *>{
0096                  new Archive::Entry(this, QStringLiteral("c.txt"), QString()),
0097                  new Archive::Entry(this, QStringLiteral("aDir/b.txt"), QStringLiteral("aDir/")),
0098              },
0099              dragAndDropOptions,
0100              2);
0101 
0102     archivePath = QFINDTESTDATA("data/one_toplevel_folder.zip");
0103     setupRow("extract the whole one_toplevel_folder.zip", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 9);
0104 
0105     archivePath = QFINDTESTDATA("data/one_toplevel_folder.zip");
0106     setupRow("extract selected entries from a zip, without paths",
0107              archivePath,
0108              QVector<Archive::Entry *>{
0109                  new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A")),
0110                  new Archive::Entry(this, QStringLiteral("A/B/test1.txt"), QStringLiteral("A/B")),
0111              },
0112              optionsNoPaths,
0113              2);
0114 
0115     archivePath = QFINDTESTDATA("data/one_toplevel_folder.zip");
0116     setupRow("extract selected entries from a zip, preserve paths",
0117              archivePath,
0118              QVector<Archive::Entry *>{
0119                  new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A")),
0120                  new Archive::Entry(this, QStringLiteral("A/B/test1.txt"), QStringLiteral("A/B")),
0121              },
0122              optionsPreservePaths,
0123              4);
0124 
0125     archivePath = QFINDTESTDATA("data/one_toplevel_folder.zip");
0126     setupRow("extract selected entries from a zip, drag-and-drop",
0127              archivePath,
0128              QVector<Archive::Entry *>{
0129                  new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A/")),
0130                  new Archive::Entry(this, QStringLiteral("A/B/C/"), QStringLiteral("A/B/")),
0131                  new Archive::Entry(this, QStringLiteral("A/B/C/test1.txt"), QStringLiteral("A/B/")),
0132                  new Archive::Entry(this, QStringLiteral("A/B/C/test2.txt"), QStringLiteral("A/B/")),
0133              },
0134              dragAndDropOptions,
0135              4);
0136 
0137     archivePath = QFINDTESTDATA("data/one_toplevel_folder.7z");
0138     setupRow("extract the whole one_toplevel_folder .7z", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 9);
0139 
0140     archivePath = QFINDTESTDATA("data/one_toplevel_folder.7z");
0141     setupRow("extract selected entries from a 7z, without paths",
0142              archivePath,
0143              QVector<Archive::Entry *>{
0144                  new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A")),
0145                  new Archive::Entry(this, QStringLiteral("A/B/test1.txt"), QStringLiteral("A/B")),
0146              },
0147              optionsNoPaths,
0148              2);
0149 
0150     archivePath = QFINDTESTDATA("data/one_toplevel_folder.7z");
0151     setupRow("extract selected entries from a 7z, preserve paths",
0152              archivePath,
0153              QVector<Archive::Entry *>{
0154                  new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A")),
0155                  new Archive::Entry(this, QStringLiteral("A/B/test1.txt"), QStringLiteral("A/B")),
0156              },
0157              optionsPreservePaths,
0158              4);
0159 
0160     archivePath = QFINDTESTDATA("data/one_toplevel_folder.7z");
0161     setupRow("extract selected entries from a 7z, drag-and-drop",
0162              archivePath,
0163              QVector<Archive::Entry *>{new Archive::Entry(this, QStringLiteral("A/B/test2.txt"), QStringLiteral("A/B/"))},
0164              dragAndDropOptions,
0165              1);
0166 
0167     archivePath = QFINDTESTDATA("data/empty_folders.zip");
0168     setupRow("zip with empty folders", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 5);
0169 
0170     archivePath = QFINDTESTDATA("data/empty_folders.tar.gz");
0171     setupRow("tar with empty folders", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 5);
0172 
0173     archivePath = QFINDTESTDATA("data/simplearchive.tar.bz2");
0174     setupRow("extract selected entries from a bzip2-compressed tarball without path",
0175              archivePath,
0176              QVector<Archive::Entry *>{
0177                  new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0178                  new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0179              },
0180              optionsNoPaths,
0181              2);
0182 
0183     archivePath = QFINDTESTDATA("data/simplearchive.tar.bz2");
0184     setupRow("extract all entries from a bzip2 - compressed tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0185 
0186     archivePath = QFINDTESTDATA("data/simplearchive.tar.xz");
0187     setupRow("extract selected entries from a xz-compressed tarball without path",
0188              archivePath,
0189              QVector<Archive::Entry *>{
0190                  new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0191                  new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0192              },
0193              optionsNoPaths,
0194              2);
0195 
0196     archivePath = QFINDTESTDATA("data/simplearchive.tar.xz");
0197     setupRow("extract all entries from a xz - compressed tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0198 
0199     archivePath = QFINDTESTDATA("data/simplearchive.tar.lzma");
0200     setupRow("extract selected entries from a lzma-compressed tarball without path",
0201              archivePath,
0202              QVector<Archive::Entry *>{
0203                  new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0204                  new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0205              },
0206              optionsNoPaths,
0207              2);
0208 
0209     archivePath = QFINDTESTDATA("data/simplearchive.tar.lzma");
0210     setupRow("extract all entries from a lzma - compressed tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0211 
0212     archivePath = QFINDTESTDATA("data/simplearchive.tar.Z");
0213     setupRow("extract selected entries from a compress (.Z)-compressed tarball without path",
0214              archivePath,
0215              QVector<Archive::Entry *>{
0216                  new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0217                  new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0218              },
0219              optionsNoPaths,
0220              2);
0221 
0222     archivePath = QFINDTESTDATA("data/simplearchive.tar.Z");
0223     setupRow("extract all entries from a compress (.Z)-compressed tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0224 
0225     archivePath = QFINDTESTDATA("data/simplearchive.tar.lz");
0226     setupRow("extract selected entries from a lzipped tarball without path",
0227              archivePath,
0228              QVector<Archive::Entry *>{
0229                  new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0230                  new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0231              },
0232              optionsNoPaths,
0233              2);
0234 
0235     archivePath = QFINDTESTDATA("data/simplearchive.tar.lz");
0236     setupRow("extract all entries from a lzipped tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0237 
0238     // Only run tests for lzop compressed files if tar.lzo format is available
0239     if (PluginManager().supportedMimeTypes().contains(QLatin1String("application/x-tzo"))) {
0240         archivePath = QFINDTESTDATA("data/simplearchive.tar.lzo");
0241         setupRow("extract selected entries from a lzop-compressed tarball without path",
0242                  archivePath,
0243                  QVector<Archive::Entry *>{
0244                      new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0245                      new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0246                  },
0247                  optionsNoPaths,
0248                  2);
0249 
0250         archivePath = QFINDTESTDATA("data/simplearchive.tar.lzo");
0251         setupRow("extract all entries from a lzop - compressed tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0252 
0253         archivePath = QFINDTESTDATA("data/test.png.lzo");
0254         setupRow("extract the single - file test.png.lzo", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0255     }
0256 
0257     // Only run tests for lrzipped files if lrzip executable is found in path.
0258     if (!QStandardPaths::findExecutable(QStringLiteral("lrzip")).isEmpty()) {
0259         archivePath = QFINDTESTDATA("data/simplearchive.tar.lrz");
0260         setupRow("extract selected entries from a lrzip-compressed tarball without path",
0261                  archivePath,
0262                  QVector<Archive::Entry *>{
0263                      new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0264                      new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0265                  },
0266                  optionsNoPaths,
0267                  2);
0268 
0269         archivePath = QFINDTESTDATA("data/simplearchive.tar.lrz");
0270         setupRow("extract all entries from a lrzip - compressed tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0271 
0272         archivePath = QFINDTESTDATA("data/test.txt.lrz");
0273         setupRow("extract the single - file test.txt.lrz", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0274     } else {
0275         qDebug() << "lrzip executable not found in path. Skipping lrzip test.";
0276     }
0277 
0278     // Only run tests for zstd-compressed files if zstd executable is found in path.
0279     if (!QStandardPaths::findExecutable(QStringLiteral("zstd")).isEmpty()) {
0280         archivePath = QFINDTESTDATA("data/simplearchive.tar.zst");
0281         setupRow("extract selected entries from a zstd-compressed tarball without path",
0282                  archivePath,
0283                  QVector<Archive::Entry *>{
0284                      new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0285                      new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0286                  },
0287                  optionsNoPaths,
0288                  2);
0289 
0290         archivePath = QFINDTESTDATA("data/simplearchive.tar.zst");
0291         setupRow("extract all entries from a zst - compressed tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0292 
0293         archivePath = QFINDTESTDATA("data/test.txt.zst");
0294         setupRow("extract the single - file test.txt.zst", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0295     } else {
0296         qDebug() << "zstd executable not found in path. Skipping zstd test.";
0297     }
0298 
0299     // Only run tests for lz4-compressed files if lz4 executable is found in path.
0300     if (!QStandardPaths::findExecutable(QStringLiteral("lz4")).isEmpty()) {
0301         archivePath = QFINDTESTDATA("data/simplearchive.tar.lz4");
0302         setupRow("extract selected entries from a lz4-compressed tarball without path",
0303                  archivePath,
0304                  QVector<Archive::Entry *>{
0305                      new Archive::Entry(this, QStringLiteral("file3.txt"), QString()),
0306                      new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()),
0307                  },
0308                  optionsNoPaths,
0309                  2);
0310 
0311         archivePath = QFINDTESTDATA("data/simplearchive.tar.lz4");
0312         setupRow("extract all entries from a lz4 - compressed tarball with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0313 
0314         archivePath = QFINDTESTDATA("data/test.txt.lz4");
0315         setupRow("extract the single - file test.txt.lz4", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0316     } else {
0317         qDebug() << "lz4 executable not found in path. Skipping lz4 test.";
0318     }
0319 
0320     archivePath = QFINDTESTDATA("data/simplearchive.xar");
0321     setupRow("extract selected entries from a xar archive without path",
0322              archivePath,
0323              QVector<Archive::Entry *>{
0324                  new Archive::Entry(this, QStringLiteral("dir1/file11.txt"), QString()),
0325                  new Archive::Entry(this, QStringLiteral("file4.txt"), QString()),
0326              },
0327              optionsNoPaths,
0328              2);
0329 
0330     archivePath = QFINDTESTDATA("data/simplearchive.xar");
0331     setupRow("extract all entries from a xar archive with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 6);
0332 
0333     archivePath = QFINDTESTDATA("data/hello-1.0-x86_64.AppImage");
0334     setupRow("extract all entries from an AppImage with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 7);
0335 
0336     archivePath = QFINDTESTDATA("data/hello-1.0-x86_64.AppImage");
0337     setupRow("extract selected entries from an AppImage with path",
0338              archivePath,
0339              QVector<Archive::Entry *>{new Archive::Entry(this, QStringLiteral("usr/bin/hello"), QString())},
0340              optionsPreservePaths,
0341              3);
0342 
0343     archivePath = QFINDTESTDATA("data/archive-multivolume.7z.001");
0344     setupRow("extract all entries from a multivolume 7z archive with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 3);
0345 
0346     archivePath = QFINDTESTDATA("data/archive-multivolume.part1.rar");
0347     setupRow("extract all entries from a multivolume rar archive with path", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 3);
0348 
0349     archivePath = QFINDTESTDATA("data/firmware-pine64-20160329-6.1.aarch64.rpm");
0350     setupRow("extract selected entries from rpm with path",
0351              archivePath,
0352              QVector<Archive::Entry *>{new Archive::Entry(this, QStringLiteral("boot/sunxi-spl.bin"), QString())},
0353              optionsPreservePaths,
0354              2);
0355 
0356     archivePath = QFINDTESTDATA("data/firmware-pine64-20160329-6.1.aarch64.rpm");
0357     setupRow("#369535: broken drag-and-drop from rpm",
0358              archivePath,
0359              QVector<Archive::Entry *>{
0360                  new Archive::Entry(this, QStringLiteral("boot/sunxi-spl.bin"), QStringLiteral("boot/")),
0361                  new Archive::Entry(this, QStringLiteral("boot/u-boot.img"), QStringLiteral("boot/")),
0362              },
0363              dragAndDropOptions,
0364              2);
0365 
0366     archivePath = QFINDTESTDATA("data/bug_#394542.zip");
0367     setupRow("#394542: libzip doesn't extract selected folder",
0368              archivePath,
0369              QVector<Archive::Entry *>{
0370                  new Archive::Entry(this, QStringLiteral("2017 - 05/")),
0371                  new Archive::Entry(this, QStringLiteral("2017 - 05/uffdå")),
0372              },
0373              optionsPreservePaths,
0374              2);
0375 
0376     archivePath = QFINDTESTDATA("data/one_toplevel_folder.arj");
0377     setupRow("extract the whole one_toplevel_folder.arj", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 9);
0378 
0379     archivePath = QFINDTESTDATA("data/one_toplevel_folder.arj");
0380     setupRow("extract selected entries from a arj, without paths",
0381              archivePath,
0382              QVector<Archive::Entry *>{
0383                  new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A")),
0384                  new Archive::Entry(this, QStringLiteral("A/B/test1.txt"), QStringLiteral("A/B")),
0385              },
0386              optionsNoPaths,
0387              2);
0388 
0389     archivePath = QFINDTESTDATA("data/one_toplevel_folder.arj");
0390     setupRow("extract selected entries from a arj, preserve paths",
0391              archivePath,
0392              QVector<Archive::Entry *>{
0393                  new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A")),
0394                  new Archive::Entry(this, QStringLiteral("A/B/test1.txt"), QStringLiteral("A/B")),
0395              },
0396              optionsPreservePaths,
0397              4);
0398 
0399     archivePath = QFINDTESTDATA("data/one_toplevel_folder.arj");
0400     setupRow("extract selected entries from a arj, drag-and-drop",
0401              archivePath,
0402              QVector<Archive::Entry *>{
0403                  new Archive::Entry(this, QStringLiteral("A/test2.txt"), QStringLiteral("A/")),
0404                  new Archive::Entry(this, QStringLiteral("A/B/C/"), QStringLiteral("A/B/")),
0405                  new Archive::Entry(this, QStringLiteral("A/B/C/test1.txt"), QStringLiteral("A/B/")),
0406                  new Archive::Entry(this, QStringLiteral("A/B/C/test2.txt"), QStringLiteral("A/B/")),
0407              },
0408              dragAndDropOptions,
0409              4);
0410 
0411     archivePath = QFINDTESTDATA("data/test.z");
0412     setupRow("extract the single - file test.z", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0413 
0414     archivePath = QFINDTESTDATA("data/test.zz");
0415     setupRow("extract the single - file test.zz", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0416 
0417     archivePath = QFINDTESTDATA("data/test.txt.gz");
0418     setupRow("extract the single - file test.txt.gz", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0419 
0420     archivePath = QFINDTESTDATA("data/test.txt.bz2");
0421     setupRow("extract the single - file test.txt.bz2", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0422 
0423     archivePath = QFINDTESTDATA("data/test.png.lzma");
0424     setupRow("extract the single - file test.png.lzma", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0425 
0426     archivePath = QFINDTESTDATA("data/test.svgz");
0427     setupRow("extract the single - file test.svgz", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0428 
0429     archivePath = QFINDTESTDATA("data/test.sit");
0430     setupRow("extract the whole test.sit", archivePath, QVector<Archive::Entry *>(), optionsPreservePaths, 1);
0431 
0432     m_expectedWorkingDir = QDir::currentPath();
0433 }
0434 
0435 void ExtractTest::testExtraction()
0436 {
0437     QFETCH(QString, archivePath);
0438     auto loadJob = Archive::load(archivePath, this);
0439     QVERIFY(loadJob);
0440     loadJob->setAutoDelete(false);
0441 
0442     TestHelper::startAndWaitForResult(loadJob);
0443     auto archive = loadJob->archive();
0444     QVERIFY(archive);
0445 
0446     if (!archive->isValid()) {
0447         QSKIP("Could not find a plugin to handle the archive. Skipping test.", SkipSingle);
0448     }
0449 
0450     QTemporaryDir destDir;
0451     if (!destDir.isValid()) {
0452         QSKIP("Could not create a temporary directory for extraction. Skipping test.", SkipSingle);
0453     }
0454 
0455     QFETCH(QVector<Archive::Entry *>, entriesToExtract);
0456     QFETCH(ExtractionOptions, extractionOptions);
0457     auto extractionJob = archive->extractFiles(entriesToExtract, destDir.path(), extractionOptions);
0458     QVERIFY(extractionJob);
0459     extractionJob->setAutoDelete(false);
0460 
0461     TestHelper::startAndWaitForResult(extractionJob);
0462 
0463     QFETCH(int, expectedExtractedEntriesCount);
0464     int extractedEntriesCount = 0;
0465 
0466     QDirIterator dirIt(destDir.path(), QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
0467     while (dirIt.hasNext()) {
0468         extractedEntriesCount++;
0469         dirIt.next();
0470     }
0471 
0472     QCOMPARE(extractedEntriesCount, expectedExtractedEntriesCount);
0473     QCOMPARE(QDir::currentPath(), m_expectedWorkingDir);
0474 
0475     loadJob->deleteLater();
0476     extractionJob->deleteLater();
0477     archive->deleteLater();
0478 }
0479 
0480 void ExtractTest::testPreservePermissions_data()
0481 {
0482     QTest::addColumn<QString>("archiveName");
0483     QTest::addColumn<Plugin *>("plugin");
0484     QTest::addColumn<QString>("testFile");
0485     QTest::addColumn<int>("expectedPermissions");
0486 
0487     // Repeat the same test case for each format and for each plugin supporting the format.
0488     const QStringList formats = TestHelper::testFormats();
0489     for (const QString &format : formats) {
0490         const QString filename = QFINDTESTDATA(QStringLiteral("data/test_permissions.%1").arg(format));
0491         const auto mime = QMimeDatabase().mimeTypeForFile(filename, QMimeDatabase::MatchExtension);
0492         const auto plugins = m_pluginManager.preferredWritePluginsFor(mime);
0493         for (const auto plugin : plugins) {
0494             QTest::newRow(QStringLiteral("test preserve 0755 permissions (%1, %2)").arg(format, plugin->metaData().pluginId()).toUtf8().constData())
0495                 << filename << plugin << QStringLiteral("0755.sh") << 0755;
0496         }
0497     }
0498 }
0499 
0500 void ExtractTest::testPreservePermissions()
0501 {
0502     QFETCH(QString, archiveName);
0503     QFETCH(Plugin *, plugin);
0504     QVERIFY(plugin);
0505     auto loadJob = Archive::load(archiveName, plugin);
0506     QVERIFY(loadJob);
0507     loadJob->setAutoDelete(false);
0508 
0509     TestHelper::startAndWaitForResult(loadJob);
0510     auto archive = loadJob->archive();
0511     QVERIFY(archive);
0512 
0513     if (!archive->isValid()) {
0514         QSKIP("Could not find a plugin to handle the archive. Skipping test.", SkipSingle);
0515     }
0516 
0517     QTemporaryDir destDir;
0518     if (!destDir.isValid()) {
0519         QSKIP("Could not create a temporary directory for extraction. Skipping test.", SkipSingle);
0520     }
0521 
0522     auto extractionJob = archive->extractFiles({}, destDir.path());
0523     QVERIFY(extractionJob);
0524     extractionJob->setAutoDelete(false);
0525     TestHelper::startAndWaitForResult(extractionJob);
0526 
0527     // Check whether extraction preserved the original permissions.
0528     QFETCH(QString, testFile);
0529     QFile file(QStringLiteral("%1/%2").arg(destDir.path(), testFile));
0530     QVERIFY(file.exists());
0531     QFETCH(int, expectedPermissions);
0532     const auto expectedQtPermissions = KIO::convertPermissions(expectedPermissions);
0533     // On Linux we get also the XXXUser flags which are ignored by KIO::convertPermissions(),
0534     // so we need to remove them before the comparison with the expected permissions.
0535     QCOMPARE(file.permissions() & expectedQtPermissions, expectedQtPermissions);
0536 
0537     loadJob->deleteLater();
0538     extractionJob->deleteLater();
0539     archive->deleteLater();
0540 }
0541 
0542 #include "extracttest.moc"