File indexing completed on 2024-04-28 05:48:12

0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0002 // SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0003 
0004 #include <QDebug>
0005 #include <QProcess>
0006 #include <QTest>
0007 
0008 #ifdef Q_OS_LINUX
0009 #include <sys/param.h>
0010 #endif
0011 
0012 #include "directoryIterator.h"
0013 #include "test-config.h"
0014 
0015 class DirectoryIteratorTest : public QObject
0016 {
0017     Q_OBJECT
0018     QString m_tree = QFINDTESTDATA("iterator-tree");
0019 private Q_SLOTS:
0020     void testIterate()
0021     {
0022 #if defined(ITERATOR_TREE_WITH_SYMLINK)
0023         const auto withSymlink = true;
0024 #else
0025         const auto withSymlink = false;
0026 #endif
0027 #if defined(ITERATOR_TREE_WITH_LINK)
0028         const auto withLink = true;
0029 #else
0030         const auto withLink = false;
0031 #endif
0032 
0033         QMap<QByteArray, DirectoryEntry> entries;
0034         for (const auto &entry : DirectoryIterator(m_tree.toUtf8())) {
0035             qDebug() << entry.name;
0036             QVERIFY(!entries.contains(entry.name));
0037             entries.insert(entry.name, entry);
0038         }
0039         qDebug() << entries.keys();
0040 
0041         auto expectedEntries = 3;
0042         if (withSymlink) {
0043             ++expectedEntries;
0044         }
0045         if (withLink) {
0046             ++expectedEntries;
0047         }
0048         QCOMPARE(entries.size(), expectedEntries);
0049 
0050         QVERIFY(entries.contains(QByteArrayLiteral("foo")));
0051 
0052         QVERIFY(entries.contains(QByteArrayLiteral("Con 자백")));
0053         const auto dir = entries[QByteArrayLiteral("Con 자백")];
0054         QVERIFY(dir.isDir);
0055         QVERIFY(!dir.isFile);
0056         QVERIFY(!dir.isSkipable);
0057         // size doesn't matter, it's ignored
0058 
0059         QVERIFY(entries.contains(QByteArrayLiteral("bar")));
0060         const auto file = entries[QByteArrayLiteral("bar")];
0061         QVERIFY(!file.isDir);
0062         QVERIFY(file.isFile);
0063         QVERIFY(!file.isSkipable);
0064 #ifdef Q_OS_WINDOWS
0065         QCOMPARE(file.size, 7682);
0066 #elif defined(Q_OS_FREEBSD)
0067         // CI keeps changing, we don't assert anything for freebsd.
0068 #else
0069         QCOMPARE(file.size, 16 * DEV_BSIZE);
0070 #endif
0071 
0072         if (withSymlink) {
0073             QVERIFY(entries.contains(QByteArrayLiteral("symlink")));
0074             const auto symlink = entries[QByteArrayLiteral("symlink")];
0075             QVERIFY(!symlink.isDir);
0076             QVERIFY(!symlink.isFile);
0077             QVERIFY(symlink.isSkipable);
0078             // size of skipables doesn't matter
0079         }
0080 
0081         if (withLink) {
0082             QVERIFY(entries.contains(QByteArrayLiteral("link")));
0083             const auto symlink = entries[QByteArrayLiteral("link")];
0084             QVERIFY(!symlink.isDir);
0085             QVERIFY(symlink.isFile);
0086             QVERIFY(!symlink.isSkipable);
0087 #ifdef Q_OS_WINDOWS
0088             QCOMPARE(symlink.size, 7682);
0089 #elif defined(Q_OS_FREEBSD)
0090             // CI keeps changing, we don't assert anything for freebsd.
0091 #else
0092             // We don't know the order, but one should be a duplicate
0093             QVERIFY(symlink.isDuplicate || file.isDuplicate);
0094             // Now make sure only one is a duplicate also
0095             QVERIFY(symlink.isDuplicate != file.isDuplicate);
0096             QCOMPARE(symlink.size, 16 * DEV_BSIZE);
0097 #endif
0098         }
0099     }
0100 
0101     void testIterateInsideUnicode()
0102     {
0103         QByteArray tree = QFINDTESTDATA("iterator-tree/Con 자백").toUtf8();
0104         QMap<QByteArray, DirectoryEntry> entries;
0105         for (const auto &entry : DirectoryIterator(tree)) {
0106             qDebug() << entry.name;
0107             QVERIFY(!entries.contains(entry.name));
0108             entries.insert(entry.name, entry);
0109         }
0110         qDebug() << entries.keys();
0111     }
0112 
0113     // During development there were some bugs with iterating C:/, make sure this finishes eventually and has some entries.
0114     void testCDrive()
0115     {
0116         QMap<QByteArray, DirectoryEntry> entries;
0117         for (const auto &entry : DirectoryIterator(m_tree.toUtf8())) {
0118             QVERIFY(!entries.contains(entry.name));
0119             entries.insert(entry.name, entry);
0120         }
0121         QVERIFY(entries.size() > 3); // windows, programs, users
0122     }
0123 
0124     void testBadPath()
0125     {
0126         for (const auto &entry : DirectoryIterator(QByteArrayLiteral("/tmp/filelighttest1312312312313123123123"))) {
0127             Q_UNUSED(entry);
0128             QVERIFY(false);
0129         }
0130     }
0131 
0132     void testSparseFile()
0133     {
0134         QTemporaryDir tmpdir;
0135         QVERIFY(tmpdir.isValid());
0136         tmpdir.path();
0137 
0138         // cppreference for std::filesystem::resize_file says it will be sparse when possible but that is a lie!
0139 #if defined(Q_OS_WINDOWS)
0140         {
0141             QProcess proc;
0142             proc.setWorkingDirectory(tmpdir.path());
0143             proc.start(QStringLiteral("fsutil"), {QStringLiteral("File"), QStringLiteral("CreateNew"), QStringLiteral("foo"), QStringLiteral("1000")});
0144             QVERIFY(proc.waitForFinished());
0145         }
0146         {
0147             QProcess proc;
0148             proc.setWorkingDirectory(tmpdir.path());
0149             proc.start(QStringLiteral("fsutil"), {QStringLiteral("Sparse"), QStringLiteral("SetFlag"), QStringLiteral("foo")});
0150             QVERIFY(proc.waitForFinished());
0151         }
0152         {
0153             QProcess proc;
0154             proc.setWorkingDirectory(tmpdir.path());
0155             proc.start(QStringLiteral("fsutil"),
0156                        {QStringLiteral("Sparse"), QStringLiteral("SetRange"), QStringLiteral("foo"), QStringLiteral("0"), QStringLiteral("1000")});
0157             QVERIFY(proc.waitForFinished());
0158         }
0159         for (const auto &entry : DirectoryIterator(tmpdir.path().toUtf8())) {
0160             QCOMPARE(entry.size, 0);
0161         }
0162 #else
0163         {
0164             QProcess proc;
0165             proc.setWorkingDirectory(tmpdir.path());
0166             proc.start(QStringLiteral("truncate"), {QStringLiteral("-s"), QStringLiteral("1K"), QStringLiteral("foo")});
0167             QVERIFY(proc.waitForFinished());
0168         }
0169 #endif
0170 
0171         bool found = false;
0172         for (const auto &entry : DirectoryIterator(tmpdir.path().toUtf8())) {
0173             QCOMPARE(entry.name, QByteArrayLiteral("foo"));
0174 #if defined(Q_OS_FREEBSD)
0175             // CI keeps changing, we don't assert anything for freebsd.
0176 #else
0177             QCOMPARE(entry.size, 0);
0178 #endif
0179             QVERIFY(!found); // only one item
0180             found = true;
0181         }
0182         QVERIFY(found);
0183     }
0184 };
0185 
0186 QTEST_GUILESS_MAIN(DirectoryIteratorTest)
0187 
0188 #include "directoryIteratorTest.moc"