1 /*
2 Copyright (C) 2005-2014 Sergey A. Tachenov
3 
4 This file is part of QuaZip test suite.
5 
6 QuaZip is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 2.1 of the License, or
9 (at your option) any later version.
10 
11 QuaZip is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU Lesser General Public License for more details.
15 
16 You should have received a copy of the GNU Lesser General Public License
17 along with QuaZip.  If not, see <http://www.gnu.org/licenses/>.
18 
19 See COPYING file for the full LGPL text.
20 
21 Original ZIP package is copyrighted by Gilles Vollant and contributors,
22 see quazip/(un)zip.h files for details. Basically it's the zlib license.
23 */
24 
25 #include "testquazip.h"
26 
27 #include "qztest.h"
28 
29 #include <QtCore/QDataStream>
30 #include <QtCore/QDir>
31 #include <QtCore/QFileInfo>
32 #include <QtCore/QHash>
33 #ifdef QUAZIP_TEST_QSAVEFILE
34 #include <QtCore/QSaveFile>
35 #endif
36 #include <QtNetwork/QTcpServer>
37 #include <QtNetwork/QTcpSocket>
38 #include <quazip_qt_compat.h>
39 
40 #include <QtTest/QtTest>
41 
42 #include <quazip.h>
43 #include <JlCompress.h>
44 
getFileList_data()45 void TestQuaZip::getFileList_data()
46 {
47     QTest::addColumn<QString>("zipName");
48     QTest::addColumn<QStringList>("fileNames");
49     QTest::newRow("simple") << "qzfilelist.zip" << (
50             QStringList() << "test0.txt" << "testdir1/test1.txt"
51             << "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt");
52     QTest::newRow("russian") << QString::fromUtf8("файл.zip") << (
53         QStringList() << QString::fromUtf8("test0.txt") << QString::fromUtf8("test1/test1.txt")
54             << "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt");
55     QTest::newRow("japanese") << QString::fromUtf8("テスト.zip") << (
56         QStringList() << QString::fromUtf8("test.txt"));
57     QTest::newRow("hebrew") << QString::fromUtf8("פתח תקווה.zip") << (
58         QStringList() << QString::fromUtf8("test.txt"));
59 }
60 
getFileList()61 void TestQuaZip::getFileList()
62 {
63     QFETCH(QString, zipName);
64     QFETCH(QStringList, fileNames);
65     fileNames.sort();
66     QDir curDir;
67     if (curDir.exists(zipName)) {
68         if (!curDir.remove(zipName))
69             QFAIL("Can't remove zip file");
70     }
71     if (!createTestFiles(fileNames)) {
72         QFAIL("Can't create test file");
73     }
74     if (!createTestArchive(zipName, fileNames)) {
75         QFAIL("Can't create test archive");
76     }
77     QuaZip testZip(zipName);
78     QVERIFY(testZip.open(QuaZip::mdUnzip));
79     QVERIFY(testZip.goToFirstFile());
80     QString firstFile = testZip.getCurrentFileName();
81     QStringList fileList = testZip.getFileNameList();
82     fileList.sort();
83     QCOMPARE(fileList, fileNames);
84     QHash<QString, QFileInfo> srcInfo;
85     foreach (QString fileName, fileNames) {
86         srcInfo[fileName] = QFileInfo("tmp/" + fileName);
87     }
88     QList<QuaZipFileInfo> destList = testZip.getFileInfoList();
89     QCOMPARE(destList.size(), srcInfo.size());
90     for (int i = 0; i < destList.size(); i++) {
91         QCOMPARE(static_cast<qint64>(destList[i].uncompressedSize),
92                 srcInfo[destList[i].name].size());
93     }
94     // Now test zip64
95     QList<QuaZipFileInfo64> destList64 = testZip.getFileInfoList64();
96     QCOMPARE(destList64.size(), srcInfo.size());
97     for (int i = 0; i < destList64.size(); i++) {
98         QCOMPARE(static_cast<qint64>(destList64[i].uncompressedSize),
99                 srcInfo[destList64[i].name].size());
100     }
101     // test that we didn't mess up the current file
102     QCOMPARE(testZip.getCurrentFileName(), firstFile);
103     testZip.close();
104     // clean up
105     removeTestFiles(fileNames);
106     curDir.remove(zipName);
107 }
108 
add_data()109 void TestQuaZip::add_data()
110 {
111     QTest::addColumn<QString>("zipName");
112     QTest::addColumn<QStringList>("fileNames");
113     QTest::addColumn<QStringList>("fileNamesToAdd");
114     QTest::newRow("simple") << "qzadd.zip" << (
115             QStringList() << "test0.txt" << "testdir1/test1.txt"
116             << "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
117             << (QStringList() << "testAdd.txt");
118 }
119 
add()120 void TestQuaZip::add()
121 {
122     QFETCH(QString, zipName);
123     QFETCH(QStringList, fileNames);
124     QFETCH(QStringList, fileNamesToAdd);
125     QDir curDir;
126     if (curDir.exists(zipName)) {
127         if (!curDir.remove(zipName))
128             QFAIL("Can't remove zip file");
129     }
130     if (!createTestFiles(fileNames)) {
131         QFAIL("Can't create test file");
132     }
133     if (!createTestArchive(zipName, fileNames)) {
134         QFAIL("Can't create test archive");
135     }
136     if (!createTestFiles(fileNamesToAdd)) {
137         QFAIL("Can't create test files to add");
138     }
139     QuaZip testZip(zipName);
140     QVERIFY(testZip.open(QuaZip::mdUnzip));
141     // according to the bug #3485459 the global is lost, so we test it
142     QString globalComment = testZip.getComment();
143     testZip.close();
144     QVERIFY(testZip.open(QuaZip::mdAdd));
145     foreach (QString fileName, fileNamesToAdd) {
146         QuaZipFile testFile(&testZip);
147         QVERIFY(testFile.open(QIODevice::WriteOnly,
148             QuaZipNewInfo(fileName, "tmp/" + fileName)));
149         QFile inFile("tmp/" + fileName);
150         QVERIFY(inFile.open(QIODevice::ReadOnly));
151         testFile.write(inFile.readAll());
152         inFile.close();
153         testFile.close();
154     }
155     testZip.close();
156     QVERIFY(testZip.open(QuaZip::mdUnzip));
157     QStringList allNames = fileNames + fileNamesToAdd;
158     QCOMPARE(testZip.getEntriesCount(), allNames.size());
159     QCOMPARE(testZip.getFileNameList(), allNames);
160     QCOMPARE(testZip.getComment(), globalComment);
161     testZip.close();
162     removeTestFiles(fileNames);
163     removeTestFiles(fileNamesToAdd);
164     curDir.remove(zipName);
165 }
166 
setFileNameCodec_data()167 void TestQuaZip::setFileNameCodec_data()
168 {
169     QTest::addColumn<QString>("zipName");
170     QTest::addColumn<QStringList>("fileNames");
171     QTest::addColumn<QByteArray>("encoding");
172     QTest::newRow("russian") << QString::fromUtf8("russian.zip") << (
173         QStringList() << QString::fromUtf8("тест.txt")) << QByteArray("IBM866");
174 }
175 
setFileNameCodec()176 void TestQuaZip::setFileNameCodec()
177 {
178     QFETCH(QString, zipName);
179     QFETCH(QStringList, fileNames);
180     QFETCH(QByteArray, encoding);
181     fileNames.sort();
182     QDir curDir;
183     if (curDir.exists(zipName)) {
184         if (!curDir.remove(zipName))
185             QFAIL("Can't remove zip file");
186     }
187     if (!createTestFiles(fileNames)) {
188         QFAIL("Can't create test file");
189     }
190     if (!createTestArchive(zipName, fileNames,
191                            QTextCodec::codecForName(encoding))) {
192         QFAIL("Can't create test archive");
193     }
194     QuaZip testZip(zipName);
195     QVERIFY(testZip.open(QuaZip::mdUnzip));
196     QStringList fileList = testZip.getFileNameList();
197     fileList.sort();
198     QVERIFY(fileList[0] != fileNames[0]);
199     testZip.close();
200     testZip.setFileNameCodec(encoding);
201     QVERIFY(testZip.open(QuaZip::mdUnzip));
202     fileList = testZip.getFileNameList();
203     fileList.sort();
204     QCOMPARE(fileList, fileNames);
205     testZip.close();
206     // clean up
207     removeTestFiles(fileNames);
208     curDir.remove(zipName);
209 }
210 
setOsCode_data()211 void TestQuaZip::setOsCode_data()
212 {
213     QTest::addColumn<QString>("zipName");
214     QTest::addColumn<uint>("osCode");
215     QTest::newRow("unix") << "unix.zip" << 3u;
216     QTest::newRow("dos") << "dos.zip" << 0u;
217 }
218 
setOsCode()219 void TestQuaZip::setOsCode()
220 {
221     QFETCH(QString, zipName);
222     QFETCH(uint, osCode);
223     QuaZip testZip(zipName);
224     testZip.setOsCode(osCode);
225     testZip.open(QuaZip::mdCreate);
226     QCOMPARE(testZip.getOsCode(), osCode);
227     QuaZipFile testZipFile(&testZip);
228     testZipFile.open(QIODevice::WriteOnly, QuaZipNewInfo("test.txt"));
229     testZipFile.close();
230     testZip.close();
231     QuaZip checkZip(zipName);
232     checkZip.open(QuaZip::mdUnzip);
233     checkZip.goToFirstFile();
234     QuaZipFileInfo64 fi;
235     QVERIFY(checkZip.getCurrentFileInfo(&fi));
236     QCOMPARE(static_cast<uint>(fi.versionCreated) >> 8, osCode);
237     checkZip.close();
238     QDir().remove(zipName);
239 }
240 
setDataDescriptorWritingEnabled()241 void TestQuaZip::setDataDescriptorWritingEnabled()
242 {
243     QString zipName = "zip10.zip";
244     QDir curDir;
245     if (curDir.exists(zipName)) {
246         if (!curDir.remove(zipName))
247             QFAIL("Can't remove zip file");
248     }
249     QuaZip testZip(zipName);
250     testZip.setDataDescriptorWritingEnabled(false);
251     QVERIFY(testZip.open(QuaZip::mdCreate));
252     QuaZipFile testZipFile(&testZip);
253     QVERIFY(testZipFile.open(QIODevice::WriteOnly,
254                              QuaZipNewInfo("vegetation_info.xml"), NULL, 0, 0));
255     QByteArray contents = "<vegetation_info version=\"4096\" />\n";
256     testZipFile.write(contents);
257     testZipFile.close();
258     testZip.close();
259     QuaZipFile readZipFile(zipName, "vegetation_info.xml");
260     QVERIFY(readZipFile.open(QIODevice::ReadOnly));
261     // Test that file is not compressed.
262     QCOMPARE(readZipFile.csize(), static_cast<qint64>(contents.size()));
263     readZipFile.close();
264     QCOMPARE(QFileInfo(zipName).size(), static_cast<qint64>(171));
265     QFile zipFile(zipName);
266     QVERIFY(zipFile.open(QIODevice::ReadOnly));
267     QDataStream zipData(&zipFile);
268     zipData.setByteOrder(QDataStream::LittleEndian);
269     quint32 magic = 0;
270     quint16 versionNeeded = 0;
271     zipData >> magic;
272     zipData >> versionNeeded;
273     QCOMPARE(magic, static_cast<quint32>(0x04034b50));
274     QCOMPARE(versionNeeded, static_cast<quint16>(10));
275     zipFile.close();
276     curDir.remove(zipName);
277     // now test 2.0
278     zipName = "zip20.zip";
279     if (curDir.exists(zipName)) {
280         if (!curDir.remove(zipName))
281             QFAIL("Can't remove zip file");
282     }
283     QuaZip testZip20(zipName);
284     QVERIFY(testZip20.open(QuaZip::mdCreate));
285     QuaZipFile testZipFile20(&testZip20);
286     QVERIFY(testZipFile20.open(QIODevice::WriteOnly,
287                              QuaZipNewInfo("vegetation_info.xml"), NULL, 0, 0));
288     testZipFile20.write("<vegetation_info version=\"4096\" />\n");
289     testZipFile20.close();
290     testZip20.close();
291     QCOMPARE(QFileInfo(zipName).size(),
292             static_cast<qint64>(171 + 16)); // 16 bytes = data descriptor
293     QFile zipFile20(zipName);
294     QVERIFY(zipFile20.open(QIODevice::ReadOnly));
295     QDataStream zipData20(&zipFile20);
296     zipData20.setByteOrder(QDataStream::LittleEndian);
297     magic = 0;
298     versionNeeded = 0;
299     zipData20 >> magic;
300     zipData20 >> versionNeeded;
301     QCOMPARE(magic, static_cast<quint32>(0x04034b50));
302     QCOMPARE(versionNeeded, static_cast<quint16>(20));
303     zipFile20.close();
304     curDir.remove(zipName);
305 }
306 
testQIODeviceAPI()307 void TestQuaZip::testQIODeviceAPI()
308 {
309     QString zipName = "qiodevice_api.zip";
310     QStringList fileNames;
311     fileNames << "test.txt";
312     QDir curDir;
313     if (curDir.exists(zipName)) {
314         if (!curDir.remove(zipName))
315             QFAIL("Can't remove zip file");
316     }
317     if (!createTestFiles(fileNames)) {
318         QFAIL("Can't create test file");
319     }
320     if (!createTestArchive(zipName, fileNames)) {
321         QFAIL("Can't create test archive");
322     }
323     QBuffer buffer;
324     if (!createTestArchive(&buffer, fileNames, NULL)) {
325         QFAIL("Can't create test archive");
326     }
327     QFile diskFile(zipName);
328     QVERIFY(diskFile.open(QIODevice::ReadOnly));
329     QByteArray bufferArray = buffer.buffer();
330     QByteArray fileArray = diskFile.readAll();
331     diskFile.close();
332     QCOMPARE(bufferArray.size(), fileArray.size());
333     QCOMPARE(bufferArray, fileArray);
334     curDir.remove(zipName);
335 }
336 
setZipName()337 void TestQuaZip::setZipName()
338 {
339     QuaZip zip;
340     zip.setZipName("testSetZipName.zip");
341     zip.open(QuaZip::mdCreate);
342     zip.close();
343     QVERIFY(QFileInfo(zip.getZipName()).exists());
344     QDir().remove(zip.getZipName());
345 }
346 
setIoDevice()347 void TestQuaZip::setIoDevice()
348 {
349     QuaZip zip;
350     QFile file("testSetIoDevice.zip");
351     zip.setIoDevice(&file);
352     QCOMPARE(zip.getIoDevice(), &file);
353     zip.open(QuaZip::mdCreate);
354     QVERIFY(file.isOpen());
355     zip.close();
356     QVERIFY(!file.isOpen());
357     QVERIFY(file.exists());
358     QDir().remove(file.fileName());
359 }
360 
setCommentCodec()361 void TestQuaZip::setCommentCodec()
362 {
363     QuaZip zip("commentCodec.zip");
364     QVERIFY(zip.open(QuaZip::mdCreate));
365     zip.setCommentCodec("WINDOWS-1251");
366     zip.setComment(QString::fromUtf8("Вопрос"));
367     QuaZipFile zipFile(&zip);
368     QVERIFY(zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo("test.txt")));
369     zipFile.close();
370     zip.close();
371     QVERIFY(zip.open(QuaZip::mdUnzip));
372     zip.setCommentCodec(QTextCodec::codecForName("KOI8-R"));
373     QCOMPARE(zip.getComment(), QString::fromUtf8("бНОПНЯ"));
374     zip.close();
375     QDir().remove(zip.getZipName());
376 }
377 
setAutoClose()378 void TestQuaZip::setAutoClose()
379 {
380     {
381         QBuffer buf;
382         QuaZip zip(&buf);
383         QVERIFY(zip.isAutoClose());
384         QVERIFY(zip.open(QuaZip::mdCreate));
385         QVERIFY(buf.isOpen());
386         zip.close();
387         QVERIFY(!buf.isOpen());
388         QVERIFY(zip.open(QuaZip::mdCreate));
389     }
390     {
391         QBuffer buf;
392         QuaZip zip(&buf);
393         QVERIFY(zip.isAutoClose());
394         zip.setAutoClose(false);
395         QVERIFY(!zip.isAutoClose());
396         QVERIFY(zip.open(QuaZip::mdCreate));
397         QVERIFY(buf.isOpen());
398         zip.close();
399         QVERIFY(buf.isOpen());
400         QVERIFY(zip.open(QuaZip::mdCreate));
401     }
402 }
403 
404 #ifdef QUAZIP_TEST_QSAVEFILE
saveFileBug()405 void TestQuaZip::saveFileBug()
406 {
407     QDir curDir;
408     QString zipName = "testSaveFile.zip";
409     if (curDir.exists(zipName)) {
410         if (!curDir.remove(zipName)) {
411             QFAIL("Can't remove testSaveFile.zip");
412         }
413     }
414     QuaZip zip;
415     QSaveFile saveFile(zipName);
416     zip.setIoDevice(&saveFile);
417     QCOMPARE(zip.getIoDevice(), &saveFile);
418     zip.open(QuaZip::mdCreate);
419     zip.close();
420     QVERIFY(QFileInfo(saveFile.fileName()).exists());
421     curDir.remove(saveFile.fileName());
422 }
423 #endif
424 
testSequential()425 void TestQuaZip::testSequential()
426 {
427     QTcpServer server;
428     QVERIFY(server.listen(QHostAddress(QHostAddress::LocalHost)));
429     quint16 port = server.serverPort();
430     QTcpSocket socket;
431     socket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
432     QVERIFY(socket.waitForConnected());
433     QVERIFY(server.waitForNewConnection(30000));
434     QTcpSocket *client = server.nextPendingConnection();
435     QuaZip zip(&socket);
436     zip.setAutoClose(false);
437     QVERIFY(zip.open(QuaZip::mdCreate));
438     QVERIFY(socket.isOpen());
439     QuaZipFile zipFile(&zip);
440     QuaZipNewInfo info("test.txt");
441     QVERIFY(zipFile.open(QIODevice::WriteOnly, info, NULL, 0, 0));
442     QCOMPARE(zipFile.write("test"), static_cast<qint64>(4));
443     zipFile.close();
444     zip.close();
445     QVERIFY(socket.isOpen());
446     socket.disconnectFromHost();
447     QVERIFY(socket.waitForDisconnected());
448     QVERIFY(client->waitForReadyRead());
449     QByteArray received = client->readAll();
450 #ifdef QUAZIP_QZTEST_QUAZIP_DEBUG_SOCKET
451     QFile debug("testSequential.zip");
452     debug.open(QIODevice::WriteOnly);
453     debug.write(received);
454     debug.close();
455 #endif
456     client->close();
457     QBuffer buffer(&received);
458     QuaZip receivedZip(&buffer);
459     QVERIFY(receivedZip.open(QuaZip::mdUnzip));
460     QVERIFY(receivedZip.goToFirstFile());
461     QuaZipFileInfo64 receivedInfo;
462     QVERIFY(receivedZip.getCurrentFileInfo(&receivedInfo));
463     QCOMPARE(receivedInfo.name, QString::fromLatin1("test.txt"));
464     QCOMPARE(receivedInfo.uncompressedSize, static_cast<quint64>(4));
465     QuaZipFile receivedFile(&receivedZip);
466     QVERIFY(receivedFile.open(QIODevice::ReadOnly));
467     QByteArray receivedText = receivedFile.readAll();
468     QCOMPARE(receivedText, QByteArray("test"));
469     receivedFile.close();
470     receivedZip.close();
471 }
472