File indexing completed on 2024-04-21 11:25:54

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2015 Luiz Romário Santana Rios <luizromario@gmail.com>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "kcompressiondevicetest.h"
0008 #include "kcompressiondevice_p.h"
0009 
0010 #include <config-compression.h>
0011 
0012 #include <QBuffer>
0013 #include <QDir>
0014 #include <QDirIterator>
0015 #include <QNetworkReply>
0016 #include <QNetworkRequest>
0017 #include <QTemporaryDir>
0018 #include <QTest>
0019 #include <QVector>
0020 
0021 QTEST_MAIN(KCompressionDeviceTest)
0022 
0023 static QString archiveFileName(const QString &extension)
0024 {
0025     return QFINDTESTDATA(QString("kcompressiondevice_test.%1").arg(extension));
0026 }
0027 
0028 QNetworkReply *KCompressionDeviceTest::getArchive(const QString &extension)
0029 {
0030     const QString kcompressionTest = archiveFileName(extension);
0031     QNetworkReply *r = qnam.get(QNetworkRequest(QUrl::fromLocalFile(kcompressionTest)));
0032 
0033     QEventLoop l;
0034     connect(&qnam, &QNetworkAccessManager::finished, &l, &QEventLoop::quit);
0035     l.exec();
0036 
0037     return r;
0038 }
0039 
0040 QString KCompressionDeviceTest::formatExtension(KCompressionDevice::CompressionType type) const
0041 {
0042     switch (type) {
0043     case KCompressionDevice::GZip:
0044         return "tar.gz";
0045     case KCompressionDevice::BZip2:
0046         return "tar.bz2";
0047     case KCompressionDevice::Xz:
0048         return "tar.xz";
0049     case KCompressionDevice::Zstd:
0050         return "tar.zst";
0051     case KCompressionDevice::None:
0052         return QString();
0053     }
0054     return QString(); // silence compiler warning
0055 }
0056 
0057 void KCompressionDeviceTest::setDeviceToArchive(QIODevice *d, KCompressionDevice::CompressionType type)
0058 {
0059     KCompressionDevice *devRawPtr = new KCompressionDevice(d, true, type);
0060     archive.reset(new KTar(devRawPtr));
0061     device.reset(devRawPtr);
0062 }
0063 
0064 void KCompressionDeviceTest::testBufferedDevice(KCompressionDevice::CompressionType type)
0065 {
0066     QNetworkReply *r = getArchive(formatExtension(type));
0067     const QByteArray data = r->readAll();
0068     QVERIFY(!data.isEmpty());
0069     const int expectedSize = QFileInfo(archiveFileName(formatExtension(type))).size();
0070     QVERIFY(expectedSize > 0);
0071     QCOMPARE(data.size(), expectedSize);
0072     QBuffer *b = new QBuffer;
0073     b->setData(data);
0074 
0075     setDeviceToArchive(b, type);
0076     testExtraction();
0077 }
0078 
0079 void KCompressionDeviceTest::testExtraction()
0080 {
0081     QTemporaryDir temp;
0082     QString oldCurrentDir = QDir::currentPath();
0083     QDir::setCurrent(temp.path());
0084 
0085     QVERIFY(archive->open(QIODevice::ReadOnly));
0086     QVERIFY(archive->directory()->copyTo("."));
0087     QVERIFY(QDir("examples").exists());
0088     QVERIFY(QDir("examples/bzip2gzip").exists());
0089     QVERIFY(QDir("examples/helloworld").exists());
0090     QVERIFY(QDir("examples/tarlocalfiles").exists());
0091     QVERIFY(QDir("examples/unzipper").exists());
0092 
0093     const QStringList fileList = {QStringLiteral("examples/bzip2gzip/CMakeLists.txt"),
0094                                   QStringLiteral("examples/bzip2gzip/main.cpp"),
0095                                   QStringLiteral("examples/helloworld/CMakeLists.txt"),
0096                                   QStringLiteral("examples/helloworld/helloworld.pro"),
0097                                   QStringLiteral("examples/helloworld/main.cpp"),
0098                                   QStringLiteral("examples/tarlocalfiles/CMakeLists.txt"),
0099                                   QStringLiteral("examples/tarlocalfiles/main.cpp"),
0100                                   QStringLiteral("examples/unzipper/CMakeLists.txt"),
0101                                   QStringLiteral("examples/unzipper/main.cpp")};
0102 
0103     for (const QString &s : fileList) {
0104         QFileInfo extractedFile(s);
0105         QFileInfo sourceFile(QFINDTESTDATA("../" + s));
0106 
0107         QVERIFY(extractedFile.exists());
0108         QCOMPARE(extractedFile.size(), sourceFile.size());
0109     }
0110     QDir::setCurrent(oldCurrentDir);
0111 }
0112 
0113 void KCompressionDeviceTest::regularKTarUsage()
0114 {
0115     archive.reset(new KTar(QFINDTESTDATA("kcompressiondevice_test.tar.gz")));
0116     device.reset();
0117 
0118     testExtraction();
0119 }
0120 
0121 void KCompressionDeviceTest::testGZipBufferedDevice()
0122 {
0123     testBufferedDevice(KCompressionDevice::GZip);
0124 }
0125 
0126 void KCompressionDeviceTest::testBZip2BufferedDevice()
0127 {
0128 #if HAVE_BZIP2_SUPPORT
0129     testBufferedDevice(KCompressionDevice::BZip2);
0130 #else
0131     QSKIP("This test needs bzip2 support");
0132 #endif
0133 }
0134 
0135 void KCompressionDeviceTest::testXzBufferedDevice()
0136 {
0137 #if HAVE_XZ_SUPPORT
0138     testBufferedDevice(KCompressionDevice::Xz);
0139 #else
0140     QSKIP("This test needs xz support");
0141 #endif
0142 }
0143 
0144 void KCompressionDeviceTest::testZstdBufferedDevice()
0145 {
0146 #ifdef HAVE_ZSTD_SUPPORT_FILE
0147     testBufferedDevice(KCompressionDevice::Zstd);
0148 #else
0149     QSKIP("This test needs zstd support");
0150 #endif
0151 }
0152 
0153 void KCompressionDeviceTest::testWriteErrorOnOpen()
0154 {
0155     // GIVEN
0156     QString fileName("/I/dont/exist/kcompressiondevicetest-write.gz");
0157     KCompressionDevice dev(fileName, KCompressionDevice::GZip);
0158     // WHEN
0159     QVERIFY(!dev.open(QIODevice::WriteOnly));
0160     // THEN
0161     QCOMPARE(dev.error(), QFileDevice::OpenError);
0162 #ifdef Q_OS_WIN
0163     QCOMPARE(dev.errorString(), QStringLiteral("The system cannot find the path specified."));
0164 #else
0165     QCOMPARE(dev.errorString(), QStringLiteral("No such file or directory"));
0166 #endif
0167 }
0168 
0169 void KCompressionDeviceTest::testWriteErrorOnClose()
0170 {
0171     // GIVEN
0172     QFile file("kcompressiondevicetest-write.gz");
0173     KCompressionDevice dev(&file, false, KCompressionDevice::GZip);
0174     QVERIFY(dev.open(QIODevice::WriteOnly));
0175     const QByteArray data = "Hello world";
0176     QCOMPARE(dev.write(data), data.size());
0177     // This is nasty, it's just a way to try and trigger an error on flush, without filling up a partition first ;)
0178     file.close();
0179     QVERIFY(file.open(QIODevice::ReadOnly));
0180     QTest::ignoreMessage(QtWarningMsg, "QIODevice::write (QFile, \"kcompressiondevicetest-write.gz\"): ReadOnly device");
0181 
0182     // WHEN
0183     dev.close(); // I want a QVERIFY here... https://bugreports.qt.io/browse/QTBUG-70033
0184 
0185     // THEN
0186     QCOMPARE(int(dev.error()), int(QFileDevice::WriteError));
0187 }
0188 
0189 void KCompressionDeviceTest::testSeekReadUncompressedBuffer_data()
0190 {
0191     QTest::addColumn<int>("dataSize");
0192     QTest::addColumn<int>("realDataPos");
0193     QTest::newRow("1.5buffer") << BUFFER_SIZE + BUFFER_SIZE / 2 << BUFFER_SIZE;
0194     QTest::newRow("5seekbuffer") << 5 * SEEK_BUFFER_SIZE << 4 * SEEK_BUFFER_SIZE;
0195 }
0196 
0197 void KCompressionDeviceTest::testSeekReadUncompressedBuffer()
0198 {
0199     QFETCH(int, dataSize);
0200     QFETCH(int, realDataPos);
0201 
0202     QByteArray ba(dataSize, 0);
0203 
0204     // all data is zero except after realDataPos that it's 0 to 9
0205     for (int i = 0; i < 10; ++i) {
0206         ba[realDataPos + i] = i;
0207     }
0208 
0209     QBuffer b;
0210     b.setData(ba);
0211     QVERIFY(b.open(QIODevice::ReadOnly));
0212 
0213     KCompressionDevice kcd(&b, false, KCompressionDevice::GZip);
0214     QVERIFY(kcd.open(QIODevice::ReadOnly));
0215     QVERIFY(kcd.seek(realDataPos));
0216 
0217     // the 10 bytes after realDataPos should be 0 to 9
0218     const QByteArray kcdData = kcd.read(10);
0219     QCOMPARE(kcdData.size(), 10);
0220     for (int i = 0; i < kcdData.size(); ++i) {
0221         QCOMPARE(kcdData[i], i);
0222     }
0223 }
0224 
0225 #include "moc_kcompressiondevicetest.cpp"