/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #if defined(Q_OS_VXWORKS) #define Q_NO_SYMLINKS #endif #if defined(Q_OS_SYMBIAN) #define Q_NO_SYMLINKS #define Q_NO_SYMLINKS_TO_DIRS #endif #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) #include "../network-settings.h" #endif Q_DECLARE_METATYPE(QDirIterator::IteratorFlags) Q_DECLARE_METATYPE(QDir::Filters) //TESTED_CLASS= //TESTED_FILES= class tst_QDirIterator : public QObject { Q_OBJECT public: tst_QDirIterator(); virtual ~tst_QDirIterator(); private: // convenience functions QStringList createdDirectories; QStringList createdFiles; QDir currentDir; bool createDirectory(const QString &dirName) { if (currentDir.mkdir(dirName)) { createdDirectories.prepend(dirName); return true; } return false; } enum Cleanup { DoDelete, DontDelete }; bool createFile(const QString &fileName, Cleanup cleanup = DoDelete) { QFile file(fileName); if (file.open(QIODevice::WriteOnly)) { if (cleanup == DoDelete) createdFiles << fileName; return true; } return false; } bool createLink(const QString &destination, const QString &linkName) { if (QFile::link(destination, linkName)) { createdFiles << linkName; return true; } return false; } private slots: void iterateRelativeDirectory_data(); void iterateRelativeDirectory(); void iterateResource_data(); void iterateResource(); void stopLinkLoop(); void engineWithNoIterator(); void absoluteFilePathsFromRelativeIteratorPath(); void recurseWithFilters() const; void longPath(); void task185502_dirorder(); void relativePaths(); #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) void uncPaths_data(); void uncPaths(); #endif }; tst_QDirIterator::tst_QDirIterator() { QFile::remove("entrylist/entrylist1.lnk"); QFile::remove("entrylist/entrylist2.lnk"); QFile::remove("entrylist/entrylist3.lnk"); QFile::remove("entrylist/entrylist4.lnk"); QFile::remove("entrylist/directory/entrylist1.lnk"); QFile::remove("entrylist/directory/entrylist2.lnk"); QFile::remove("entrylist/directory/entrylist3.lnk"); QFile::remove("entrylist/directory/entrylist4.lnk"); createDirectory("entrylist"); createDirectory("entrylist/directory"); createFile("entrylist/file", DontDelete); createFile("entrylist/writable"); createFile("entrylist/directory/dummy", DontDelete); createDirectory("recursiveDirs"); createDirectory("recursiveDirs/dir1"); createFile("recursiveDirs/textFileA.txt"); createFile("recursiveDirs/dir1/aPage.html"); createFile("recursiveDirs/dir1/textFileB.txt"); createDirectory("foo"); createDirectory("foo/bar"); createFile("foo/bar/readme.txt"); createDirectory("empty"); #ifndef Q_NO_SYMLINKS # if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) // ### Sadly, this is a platform difference right now. createLink("entrylist/file", "entrylist/linktofile.lnk"); # ifndef Q_NO_SYMLINKS_TO_DIRS createLink("entrylist/directory", "entrylist/linktodirectory.lnk"); # endif createLink("entrylist/nothing", "entrylist/brokenlink.lnk"); # else createLink("file", "entrylist/linktofile.lnk"); # ifndef Q_NO_SYMLINKS_TO_DIRS createLink("directory", "entrylist/linktodirectory.lnk"); # endif createLink("nothing", "entrylist/brokenlink.lnk"); # endif #endif } tst_QDirIterator::~tst_QDirIterator() { Q_FOREACH(QString fileName, createdFiles) QFile::remove(fileName); Q_FOREACH(QString dirName, createdDirectories) currentDir.rmdir(dirName); } void tst_QDirIterator::iterateRelativeDirectory_data() { QTest::addColumn("dirName"); // relative from current path or abs QTest::addColumn("flags"); QTest::addColumn("filters"); QTest::addColumn("nameFilters"); QTest::addColumn("entries"); QTest::newRow("no flags") << QString("entrylist") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList("*") << QString( #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) "entrylist/.," "entrylist/..," #endif "entrylist/file," #ifndef Q_NO_SYMLINKS "entrylist/linktofile.lnk," #endif "entrylist/directory," #if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) "entrylist/linktodirectory.lnk," #endif "entrylist/writable").split(','); QTest::newRow("NoDot") << QString("entrylist") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::AllEntries | QDir::NoDot) << QStringList("*") << QString( #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) "entrylist/..," #endif "entrylist/file," #ifndef Q_NO_SYMLINKS "entrylist/linktofile.lnk," #endif "entrylist/directory," #if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) "entrylist/linktodirectory.lnk," #endif "entrylist/writable").split(','); QTest::newRow("NoDotDot") << QString("entrylist") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::AllEntries | QDir::NoDotDot) << QStringList("*") << QString( #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) "entrylist/.," #endif "entrylist/file," #ifndef Q_NO_SYMLINKS "entrylist/linktofile.lnk," #endif "entrylist/directory," #if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) "entrylist/linktodirectory.lnk," #endif "entrylist/writable").split(','); QTest::newRow("NoDotAndDotDot") << QString("entrylist") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::AllEntries | QDir::NoDotAndDotDot) << QStringList("*") << QString( "entrylist/file," #ifndef Q_NO_SYMLINKS "entrylist/linktofile.lnk," #endif "entrylist/directory," #if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) "entrylist/linktodirectory.lnk," #endif "entrylist/writable").split(','); QTest::newRow("QDir::Subdirectories | QDir::FollowSymlinks") << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories | QDirIterator::FollowSymlinks) << QDir::Filters(QDir::NoFilter) << QStringList("*") << QString( #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) "entrylist/.," "entrylist/..," "entrylist/directory/.," "entrylist/directory/..," #endif "entrylist/file," #ifndef Q_NO_SYMLINKS "entrylist/linktofile.lnk," #endif "entrylist/directory," "entrylist/directory/dummy," #if !defined(Q_NO_SYMLINKS) && !defined(Q_NO_SYMLINKS_TO_DIRS) "entrylist/linktodirectory.lnk," #endif "entrylist/writable").split(','); QTest::newRow("QDir::Subdirectories / QDir::Files") << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories) << QDir::Filters(QDir::Files) << QStringList("*") << QString("entrylist/directory/dummy," "entrylist/file," #ifndef Q_NO_SYMLINKS "entrylist/linktofile.lnk," #endif "entrylist/writable").split(','); QTest::newRow("QDir::Subdirectories | QDir::FollowSymlinks / QDir::Files") << QString("entrylist") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories | QDirIterator::FollowSymlinks) << QDir::Filters(QDir::Files) << QStringList("*") << QString("entrylist/file," #ifndef Q_NO_SYMLINKS "entrylist/linktofile.lnk," #endif "entrylist/directory/dummy," "entrylist/writable").split(','); QTest::newRow("empty, default") << QString("empty") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList("*") #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) << QStringList(); #else << QString("empty/.,empty/..").split(','); #endif QTest::newRow("empty, QDir::NoDotAndDotDot") << QString("empty") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoDotAndDotDot) << QStringList("*") << QStringList(); } void tst_QDirIterator::iterateRelativeDirectory() { QFETCH(QString, dirName); QFETCH(QDirIterator::IteratorFlags, flags); QFETCH(QDir::Filters, filters); QFETCH(QStringList, nameFilters); QFETCH(QStringList, entries); QDirIterator it(dirName, nameFilters, filters, flags); QStringList list; while (it.hasNext()) { QString next = it.next(); QString fileName = it.fileName(); QString filePath = it.filePath(); QString path = it.path(); QFileInfo info = it.fileInfo(); QCOMPARE(path, dirName); QCOMPARE(next, filePath); QCOMPARE(info, QFileInfo(next)); QCOMPARE(fileName, info.fileName()); QCOMPARE(filePath, info.filePath()); // Using canonical file paths for final comparison list << info.canonicalFilePath(); } // The order of items returned by QDirIterator is not guaranteed. list.sort(); QStringList sortedEntries; foreach(QString item, entries) sortedEntries.append(QFileInfo(item).canonicalFilePath()); sortedEntries.sort(); if (sortedEntries != list) { qDebug() << "EXPECTED:" << sortedEntries; qDebug() << "ACTUAL: " << list; } QCOMPARE(list, sortedEntries); } void tst_QDirIterator::iterateResource_data() { QTest::addColumn("dirName"); // relative from current path or abs QTest::addColumn("flags"); QTest::addColumn("filters"); QTest::addColumn("nameFilters"); QTest::addColumn("entries"); QTest::newRow("invalid") << QString::fromLatin1(":/burpaburpa") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) << QStringList(); QTest::newRow(":/") << QString::fromLatin1(":/") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) << QString::fromLatin1(":/entrylist").split(QLatin1String(",")); QTest::newRow(":/entrylist") << QString::fromLatin1(":/entrylist") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) << QString::fromLatin1(":/entrylist/directory,:/entrylist/file").split(QLatin1String(",")); QTest::newRow(":/ recursive") << QString::fromLatin1(":/") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) << QString::fromLatin1(":/entrylist,:/entrylist/directory,:/entrylist/directory/dummy,:/entrylist/file").split(QLatin1String(",")); } void tst_QDirIterator::iterateResource() { QFETCH(QString, dirName); QFETCH(QDirIterator::IteratorFlags, flags); QFETCH(QDir::Filters, filters); QFETCH(QStringList, nameFilters); QFETCH(QStringList, entries); QDirIterator it(dirName, nameFilters, filters, flags); QStringList list; while (it.hasNext()) list << it.next(); list.sort(); QStringList sortedEntries = entries; sortedEntries.sort(); if (sortedEntries != list) { qDebug() << "EXPECTED:" << sortedEntries; qDebug() << "ACTUAL:" << list; } QCOMPARE(list, sortedEntries); } void tst_QDirIterator::stopLinkLoop() { #ifdef Q_OS_WIN // ### Sadly, this is a platform difference right now. createLink(QDir::currentPath() + QLatin1String("/entrylist"), "entrylist/entrylist1.lnk"); createLink("entrylist/.", "entrylist/entrylist2.lnk"); createLink("entrylist/../entrylist/.", "entrylist/entrylist3.lnk"); createLink("entrylist/..", "entrylist/entrylist4.lnk"); createLink(QDir::currentPath() + QLatin1String("/entrylist"), "entrylist/directory/entrylist1.lnk"); createLink("entrylist/.", "entrylist/directory/entrylist2.lnk"); createLink("entrylist/../directory/.", "entrylist/directory/entrylist3.lnk"); createLink("entrylist/..", "entrylist/directory/entrylist4.lnk"); #else createLink(QDir::currentPath() + QLatin1String("/entrylist"), "entrylist/entrylist1.lnk"); createLink(".", "entrylist/entrylist2.lnk"); createLink("../entrylist/.", "entrylist/entrylist3.lnk"); createLink("..", "entrylist/entrylist4.lnk"); createLink(QDir::currentPath() + QLatin1String("/entrylist"), "entrylist/directory/entrylist1.lnk"); createLink(".", "entrylist/directory/entrylist2.lnk"); createLink("../directory/.", "entrylist/directory/entrylist3.lnk"); createLink("..", "entrylist/directory/entrylist4.lnk"); #endif QDirIterator it(QLatin1String("entrylist"), QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); QStringList list; int max = 200; while (--max && it.hasNext()) it.next(); QVERIFY(max); // The goal of this test is only to ensure that the test above don't malfunction } class EngineWithNoIterator : public QFSFileEngine { public: EngineWithNoIterator(const QString &fileName) : QFSFileEngine(fileName) { } QAbstractFileEngineIterator *beginEntryList(QDir::Filters, const QStringList &) { return 0; } }; class EngineWithNoIteratorHandler : public QAbstractFileEngineHandler { public: QAbstractFileEngine *create(const QString &fileName) const { return new EngineWithNoIterator(fileName); } }; void tst_QDirIterator::engineWithNoIterator() { EngineWithNoIteratorHandler handler; QDir("entrylist").entryList(); QVERIFY(true); // test that the above line doesn't crash } void tst_QDirIterator::absoluteFilePathsFromRelativeIteratorPath() { QDirIterator it("entrylist/", QDir::NoDotAndDotDot); while (it.hasNext()) { it.next(); QVERIFY(QFileInfo(it.filePath()).absoluteFilePath().contains("entrylist")); } } void tst_QDirIterator::recurseWithFilters() const { QStringList nameFilters; nameFilters.append("*.txt"); QDirIterator it("recursiveDirs/", nameFilters, QDir::Files, QDirIterator::Subdirectories); QSet actualEntries; QSet expectedEntries; expectedEntries.insert(QString::fromLatin1("recursiveDirs/dir1/textFileB.txt")); expectedEntries.insert(QString::fromLatin1("recursiveDirs/textFileA.txt")); QVERIFY(it.hasNext()); it.next(); actualEntries.insert(it.fileInfo().filePath()); QVERIFY(it.hasNext()); it.next(); actualEntries.insert(it.fileInfo().filePath()); QVERIFY(actualEntries == expectedEntries); QVERIFY(!it.hasNext()); } void tst_QDirIterator::longPath() { QDir dir; dir.mkdir("longpaths"); dir.cd("longpaths"); QString dirName = "x"; int n = 0; while (dir.exists(dirName) || dir.mkdir(dirName)) { ++n; dirName.append('x'); #if defined(Q_OS_WINCE) && defined(WINCE_BROKEN_ITERATE) // Some Windows CE devices/emulators are broken. // though one can create directories of length <= 217, // FindNextFile only reports entries until ~ 214. if (n >= 210) break; #endif } QDirIterator it(dir.absolutePath(), QDir::NoDotAndDotDot|QDir::Dirs, QDirIterator::Subdirectories); int m = 0; while (it.hasNext()) { ++m; it.next(); } QCOMPARE(n, m); dirName.chop(1); while (dirName.length() > 0 && dir.exists(dirName) && dir.rmdir(dirName)) { dirName.chop(1); } dir.cdUp(); dir.rmdir("longpaths"); } void tst_QDirIterator::task185502_dirorder() { QDirIterator iterator("foo", QDirIterator::Subdirectories); while (iterator.hasNext() && iterator.next() != "foo/bar") { } QCOMPARE(iterator.filePath(), QString("foo/bar")); QCOMPARE(iterator.fileInfo().filePath(), QString("foo/bar")); } void tst_QDirIterator::relativePaths() { QDirIterator iterator("*", QDirIterator::Subdirectories); while(iterator.hasNext()) { QCOMPARE(iterator.filePath(), QDir::cleanPath(iterator.filePath())); } } #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) void tst_QDirIterator::uncPaths_data() { QTest::addColumn("dirName"); QTest::newRow("uncserver") <