Copy QDirIterator.{cpp,h} to QDirListing.{cpp,h}
To make it easier to follow the history in git. Change-Id: I094056c1ec130aeef77aa2d20289ab766bc25083 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
6c424dbcb0
commit
78c33a7741
28
src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp
Normal file
28
src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
//! [0]
|
||||
QDirIterator it("/etc", QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QString dir = it.next();
|
||||
qDebug() << dir;
|
||||
// /etc/.
|
||||
// /etc/..
|
||||
// /etc/X11
|
||||
// /etc/X11/fs
|
||||
// ...
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
QDirIterator it("/sys", QStringList() << "scaling_cur_freq", QDir::NoFilter, QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QFile f(it.next());
|
||||
f.open(QIODevice::ReadOnly);
|
||||
qDebug() << f.fileName() << f.readAll().trimmed().toDouble() / 1000 << "MHz";
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
QDirIterator audioFileIt(audioPath, {"*.mp3", "*.wav"}, QDir::Files);
|
||||
//! [2]
|
575
src/corelib/io/qdirlisting.cpp
Normal file
575
src/corelib/io/qdirlisting.cpp
Normal file
@ -0,0 +1,575 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
/*!
|
||||
\since 4.3
|
||||
\class QDirIterator
|
||||
\inmodule QtCore
|
||||
\brief The QDirIterator class provides an iterator for directory entrylists.
|
||||
|
||||
You can use QDirIterator to navigate entries of a directory one at a time.
|
||||
It is similar to QDir::entryList() and QDir::entryInfoList(), but because
|
||||
it lists entries one at a time instead of all at once, it scales better
|
||||
and is more suitable for large directories. It also supports listing
|
||||
directory contents recursively, and following symbolic links. Unlike
|
||||
QDir::entryList(), QDirIterator does not support sorting.
|
||||
|
||||
The QDirIterator constructor takes a QDir or a directory as
|
||||
argument. After construction, the iterator is located before the first
|
||||
directory entry. Here's how to iterate over all the entries sequentially:
|
||||
|
||||
\snippet code/src_corelib_io_qdiriterator.cpp 0
|
||||
|
||||
Here's how to find and read all files filtered by name, recursively:
|
||||
|
||||
\snippet code/src_corelib_io_qdiriterator.cpp 1
|
||||
|
||||
The next() and nextFileInfo() functions advance the iterator and return
|
||||
the path or the QFileInfo of the next directory entry. You can also call
|
||||
filePath() or fileInfo() to get the current file path or QFileInfo without
|
||||
first advancing the iterator. The fileName() function returns only the
|
||||
name of the file, similar to how QDir::entryList() works.
|
||||
|
||||
Unlike Qt's container iterators, QDirIterator is uni-directional (i.e.,
|
||||
you cannot iterate directories in reverse order) and does not allow random
|
||||
access.
|
||||
|
||||
\sa QDir, QDir::entryList()
|
||||
*/
|
||||
|
||||
/*! \enum QDirIterator::IteratorFlag
|
||||
|
||||
This enum describes flags that you can combine to configure the behavior
|
||||
of QDirIterator.
|
||||
|
||||
\value NoIteratorFlags The default value, representing no flags. The
|
||||
iterator will return entries for the assigned path.
|
||||
|
||||
\value Subdirectories List entries inside all subdirectories as well.
|
||||
|
||||
\value FollowSymlinks When combined with Subdirectories, this flag
|
||||
enables iterating through all subdirectories of the assigned path,
|
||||
following all symbolic links. Symbolic link loops (e.g., "link" => "." or
|
||||
"link" => "..") are automatically detected and ignored.
|
||||
*/
|
||||
|
||||
#include "qdiriterator.h"
|
||||
#include "qdir_p.h"
|
||||
#include "qabstractfileengine_p.h"
|
||||
|
||||
#include <QtCore/qset.h>
|
||||
#include <QtCore/qstack.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#if QT_CONFIG(regularexpression)
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#endif
|
||||
|
||||
#include <QtCore/private/qfilesystemiterator_p.h>
|
||||
#include <QtCore/private/qfilesystementry_p.h>
|
||||
#include <QtCore/private/qfilesystemmetadata_p.h>
|
||||
#include <QtCore/private/qfilesystemengine_p.h>
|
||||
#include <QtCore/private/qfileinfo_p.h>
|
||||
#include <QtCore/private/qduplicatetracker_p.h>
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
class QDirIteratorPrivate
|
||||
{
|
||||
public:
|
||||
void init(bool resolveEngine);
|
||||
void advance();
|
||||
|
||||
bool entryMatches(const QString & fileName, const QFileInfo &fileInfo);
|
||||
void pushDirectory(const QFileInfo &fileInfo);
|
||||
void checkAndPushDirectory(const QFileInfo &);
|
||||
bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
|
||||
|
||||
std::unique_ptr<QAbstractFileEngine> engine;
|
||||
|
||||
QFileSystemEntry dirEntry;
|
||||
QStringList nameFilters;
|
||||
QDir::Filters filters;
|
||||
QDirIterator::IteratorFlags iteratorFlags;
|
||||
|
||||
#if QT_CONFIG(regularexpression)
|
||||
QList<QRegularExpression> nameRegExps;
|
||||
#endif
|
||||
|
||||
using FEngineIteratorPtr = std::unique_ptr<QAbstractFileEngineIterator>;
|
||||
std::stack<FEngineIteratorPtr, std::vector<FEngineIteratorPtr>> fileEngineIterators;
|
||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
||||
using FsIteratorPtr = std::unique_ptr<QFileSystemIterator>;
|
||||
std::stack<FsIteratorPtr, std::vector<FsIteratorPtr>> nativeIterators;
|
||||
#endif
|
||||
|
||||
QFileInfo currentFileInfo;
|
||||
QFileInfo nextFileInfo;
|
||||
|
||||
// Loop protection
|
||||
QDuplicateTracker<QString> visitedLinks;
|
||||
};
|
||||
|
||||
void QDirIteratorPrivate::init(bool resolveEngine = true)
|
||||
{
|
||||
if (nameFilters.contains("*"_L1))
|
||||
nameFilters.clear();
|
||||
|
||||
if (filters == QDir::NoFilter)
|
||||
filters = QDir::AllEntries;
|
||||
|
||||
#if QT_CONFIG(regularexpression)
|
||||
nameRegExps.reserve(nameFilters.size());
|
||||
for (const auto &filter : nameFilters) {
|
||||
auto re = QRegularExpression::fromWildcard(filter, (filters & QDir::CaseSensitive ?
|
||||
Qt::CaseSensitive : Qt::CaseInsensitive));
|
||||
nameRegExps.append(re);
|
||||
}
|
||||
#endif
|
||||
QFileSystemMetaData metaData;
|
||||
if (resolveEngine)
|
||||
engine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData));
|
||||
QFileInfo fileInfo(new QFileInfoPrivate(dirEntry, metaData));
|
||||
|
||||
// Populate fields for hasNext() and next()
|
||||
pushDirectory(fileInfo);
|
||||
advance();
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
|
||||
{
|
||||
QString path = fileInfo.filePath();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (fileInfo.isSymLink())
|
||||
path = fileInfo.canonicalFilePath();
|
||||
#endif
|
||||
|
||||
if ((iteratorFlags & QDirIterator::FollowSymlinks)) {
|
||||
// Stop link loops
|
||||
if (visitedLinks.hasSeen(fileInfo.canonicalFilePath()))
|
||||
return;
|
||||
}
|
||||
|
||||
if (engine) {
|
||||
engine->setFileName(path);
|
||||
QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
|
||||
if (it) {
|
||||
it->setPath(path);
|
||||
fileEngineIterators.emplace(FEngineIteratorPtr(it));
|
||||
} else {
|
||||
// No iterator; no entry list.
|
||||
}
|
||||
} else {
|
||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
||||
nativeIterators.emplace(std::make_unique<QFileSystemIterator>(
|
||||
fileInfo.d_ptr->fileEntry, filters));
|
||||
#else
|
||||
qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline bool QDirIteratorPrivate::entryMatches(const QString & fileName, const QFileInfo &fileInfo)
|
||||
{
|
||||
checkAndPushDirectory(fileInfo);
|
||||
|
||||
if (matchesFilters(fileName, fileInfo)) {
|
||||
currentFileInfo = nextFileInfo;
|
||||
nextFileInfo = fileInfo;
|
||||
|
||||
//We found a matching entry.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
||||
Advances the internal iterator, either a QAbstractFileEngineIterator (e.g.
|
||||
QResourceFileEngineIterator) or a QFileSystemIterator (which uses low-level
|
||||
system methods, e.g. readdir() on Unix).
|
||||
|
||||
An iterator stack is used for holding the iterators.
|
||||
|
||||
A typical example of doing recursive iteration:
|
||||
- while iterating directory A we find a sub-dir B
|
||||
- an iterator for B is added to the iterator stack
|
||||
- B's iterator is processed (the top() of the stack) first; then loop
|
||||
goes back to processing A's iterator
|
||||
*/
|
||||
void QDirIteratorPrivate::advance()
|
||||
{
|
||||
// Use get() in both code paths below because the iterator returned by top()
|
||||
// may be invalidated due to reallocation when appending new iterators in
|
||||
// pushDirectory().
|
||||
|
||||
if (engine) {
|
||||
while (!fileEngineIterators.empty()) {
|
||||
// Find the next valid iterator that matches the filters.
|
||||
QAbstractFileEngineIterator *it;
|
||||
while (it = fileEngineIterators.top().get(), it->hasNext()) {
|
||||
it->next();
|
||||
if (entryMatches(it->currentFileName(), it->currentFileInfo()))
|
||||
return;
|
||||
}
|
||||
|
||||
fileEngineIterators.pop();
|
||||
}
|
||||
} else {
|
||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
||||
QFileSystemEntry nextEntry;
|
||||
QFileSystemMetaData nextMetaData;
|
||||
|
||||
while (!nativeIterators.empty()) {
|
||||
// Find the next valid iterator that matches the filters.
|
||||
QFileSystemIterator *it;
|
||||
while (it = nativeIterators.top().get(), it->advance(nextEntry, nextMetaData)) {
|
||||
QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData));
|
||||
|
||||
if (entryMatches(nextEntry.fileName(), info))
|
||||
return;
|
||||
nextMetaData = QFileSystemMetaData();
|
||||
}
|
||||
|
||||
nativeIterators.pop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
currentFileInfo = nextFileInfo;
|
||||
nextFileInfo = QFileInfo();
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo)
|
||||
{
|
||||
// If we're doing flat iteration, we're done.
|
||||
if (!(iteratorFlags & QDirIterator::Subdirectories))
|
||||
return;
|
||||
|
||||
// Never follow non-directory entries
|
||||
if (!fileInfo.isDir())
|
||||
return;
|
||||
|
||||
// Follow symlinks only when asked
|
||||
if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink())
|
||||
return;
|
||||
|
||||
// Never follow . and ..
|
||||
QString fileName = fileInfo.fileName();
|
||||
if ("."_L1 == fileName || ".."_L1 == fileName)
|
||||
return;
|
||||
|
||||
// No hidden directories unless requested
|
||||
if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden())
|
||||
return;
|
||||
|
||||
pushDirectory(fileInfo);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
||||
This convenience function implements the iterator's filtering logics and
|
||||
applies then to the current directory entry.
|
||||
|
||||
It returns \c true if the current entry matches the filters (i.e., the
|
||||
current entry will be returned as part of the directory iteration);
|
||||
otherwise, false is returned.
|
||||
*/
|
||||
|
||||
bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const
|
||||
{
|
||||
if (fileName.isEmpty())
|
||||
return false;
|
||||
|
||||
// filter . and ..?
|
||||
const qsizetype fileNameSize = fileName.size();
|
||||
const bool dotOrDotDot = fileName[0] == u'.'
|
||||
&& ((fileNameSize == 1)
|
||||
||(fileNameSize == 2 && fileName[1] == u'.'));
|
||||
if ((filters & QDir::NoDot) && dotOrDotDot && fileNameSize == 1)
|
||||
return false;
|
||||
if ((filters & QDir::NoDotDot) && dotOrDotDot && fileNameSize == 2)
|
||||
return false;
|
||||
|
||||
// name filter
|
||||
#if QT_CONFIG(regularexpression)
|
||||
// Pass all entries through name filters, except dirs if the AllDirs
|
||||
if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) {
|
||||
bool matched = false;
|
||||
for (const auto &re : nameRegExps) {
|
||||
if (re.match(fileName).hasMatch()) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// skip symlinks
|
||||
const bool skipSymlinks = filters.testAnyFlag(QDir::NoSymLinks);
|
||||
const bool includeSystem = filters.testAnyFlag(QDir::System);
|
||||
if (skipSymlinks && fi.isSymLink()) {
|
||||
// The only reason to save this file is if it is a broken link and we are requesting system files.
|
||||
if (!includeSystem || fi.exists())
|
||||
return false;
|
||||
}
|
||||
|
||||
// filter hidden
|
||||
const bool includeHidden = filters.testAnyFlag(QDir::Hidden);
|
||||
if (!includeHidden && !dotOrDotDot && fi.isHidden())
|
||||
return false;
|
||||
|
||||
// filter system files
|
||||
if (!includeSystem && (!(fi.isFile() || fi.isDir() || fi.isSymLink())
|
||||
|| (!fi.exists() && fi.isSymLink())))
|
||||
return false;
|
||||
|
||||
// skip directories
|
||||
const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
|
||||
if (skipDirs && fi.isDir())
|
||||
return false;
|
||||
|
||||
// skip files
|
||||
const bool skipFiles = !(filters & QDir::Files);
|
||||
if (skipFiles && fi.isFile())
|
||||
// Basically we need a reason not to exclude this file otherwise we just eliminate it.
|
||||
return false;
|
||||
|
||||
// filter permissions
|
||||
const bool filterPermissions = ((filters & QDir::PermissionMask)
|
||||
&& (filters & QDir::PermissionMask) != QDir::PermissionMask);
|
||||
const bool doWritable = !filterPermissions || (filters & QDir::Writable);
|
||||
const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
|
||||
const bool doReadable = !filterPermissions || (filters & QDir::Readable);
|
||||
if (filterPermissions
|
||||
&& ((doReadable && !fi.isReadable())
|
||||
|| (doWritable && !fi.isWritable())
|
||||
|| (doExecutable && !fi.isExecutable()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QDirIterator that can iterate over \a dir's entrylist, using
|
||||
\a dir's name filters and regular filters. You can pass options via \a
|
||||
flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as in QDir::entryList().
|
||||
|
||||
The sorting in \a dir is ignored.
|
||||
|
||||
\note To list symlinks that point to non existing files, QDir::System must be
|
||||
passed to the flags.
|
||||
|
||||
\sa hasNext(), next(), IteratorFlags
|
||||
*/
|
||||
QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
|
||||
: d(new QDirIteratorPrivate)
|
||||
{
|
||||
const QDirPrivate *other = dir.d_ptr.constData();
|
||||
d->dirEntry = other->dirEntry;
|
||||
d->nameFilters = other->nameFilters;
|
||||
d->filters = other->filters;
|
||||
d->iteratorFlags = flags;
|
||||
const bool resolveEngine = other->fileEngine ? true : false;
|
||||
d->init(resolveEngine);
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QDirIterator that can iterate over \a path, with no name
|
||||
filtering and \a filters for entry filtering. You can pass options via \a
|
||||
flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
|
||||
which provides the same behavior as in QDir::entryList().
|
||||
|
||||
\note To list symlinks that point to non existing files, QDir::System must be
|
||||
passed to the flags.
|
||||
|
||||
\sa hasNext(), next(), IteratorFlags
|
||||
*/
|
||||
QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
|
||||
: d(new QDirIteratorPrivate)
|
||||
{
|
||||
d->dirEntry = QFileSystemEntry(path);
|
||||
d->filters = filters;
|
||||
d->iteratorFlags = flags;
|
||||
d->init();
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QDirIterator that can iterate over \a path. You can pass
|
||||
options via \a flags to decide how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as in QDir::entryList().
|
||||
|
||||
\note To list symlinks that point to non existing files, QDir::System must be
|
||||
passed to the flags.
|
||||
|
||||
\sa hasNext(), next(), IteratorFlags
|
||||
*/
|
||||
QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
|
||||
: d(new QDirIteratorPrivate)
|
||||
{
|
||||
d->dirEntry = QFileSystemEntry(path);
|
||||
d->filters = QDir::NoFilter;
|
||||
d->iteratorFlags = flags;
|
||||
d->init();
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QDirIterator that can iterate over \a path, using \a
|
||||
nameFilters and \a filters. You can pass options via \a flags to decide
|
||||
how the directory should be iterated.
|
||||
|
||||
By default, \a flags is NoIteratorFlags, which provides the same behavior
|
||||
as QDir::entryList().
|
||||
|
||||
For example, the following iterator could be used to iterate over audio
|
||||
files:
|
||||
|
||||
\snippet code/src_corelib_io_qdiriterator.cpp 2
|
||||
|
||||
\note To list symlinks that point to non existing files, QDir::System must be
|
||||
passed to the flags.
|
||||
|
||||
\sa hasNext(), next(), IteratorFlags, QDir::setNameFilters()
|
||||
*/
|
||||
QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
|
||||
QDir::Filters filters, IteratorFlags flags)
|
||||
: d(new QDirIteratorPrivate)
|
||||
{
|
||||
d->dirEntry = QFileSystemEntry(path);
|
||||
d->nameFilters = nameFilters;
|
||||
d->filters = filters;
|
||||
d->iteratorFlags = flags;
|
||||
d->init();
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys the QDirIterator.
|
||||
*/
|
||||
QDirIterator::~QDirIterator()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Advances the iterator to the next entry, and returns the file path of this
|
||||
new entry. If hasNext() returns \c false, this function does nothing, and
|
||||
returns an empty QString.
|
||||
|
||||
You can call fileName() or filePath() to get the current entry's file name
|
||||
or path, or fileInfo() to get a QFileInfo for the current entry.
|
||||
|
||||
Call nextFileInfo() instead of next() if you're interested in the QFileInfo.
|
||||
|
||||
\sa hasNext(), nextFileInfo(), fileName(), filePath(), fileInfo()
|
||||
*/
|
||||
QString QDirIterator::next()
|
||||
{
|
||||
d->advance();
|
||||
return filePath();
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.3
|
||||
|
||||
Advances the iterator to the next entry, and returns the file info of this
|
||||
new entry. If hasNext() returns \c false, this function does nothing, and
|
||||
returns an empty QFileInfo.
|
||||
|
||||
You can call fileName() or filePath() to get the current entry's file name
|
||||
or path, or fileInfo() to get a QFileInfo for the current entry.
|
||||
|
||||
Call next() instead of nextFileInfo() when all you need is the filePath().
|
||||
|
||||
\sa hasNext(), fileName(), filePath(), fileInfo()
|
||||
*/
|
||||
QFileInfo QDirIterator::nextFileInfo()
|
||||
{
|
||||
d->advance();
|
||||
return fileInfo();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c true if there is at least one more entry in the directory;
|
||||
otherwise, false is returned.
|
||||
|
||||
\sa next(), nextFileInfo(), fileName(), filePath(), fileInfo()
|
||||
*/
|
||||
bool QDirIterator::hasNext() const
|
||||
{
|
||||
if (d->engine)
|
||||
return !d->fileEngineIterators.empty();
|
||||
else
|
||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
||||
return !d->nativeIterators.empty();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the file name for the current directory entry, without the path
|
||||
prepended.
|
||||
|
||||
This function is convenient when iterating a single directory. When using
|
||||
the QDirIterator::Subdirectories flag, you can use filePath() to get the
|
||||
full path.
|
||||
|
||||
\sa filePath(), fileInfo()
|
||||
*/
|
||||
QString QDirIterator::fileName() const
|
||||
{
|
||||
return d->currentFileInfo.fileName();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the full file path for the current directory entry.
|
||||
|
||||
\sa fileInfo(), fileName()
|
||||
*/
|
||||
QString QDirIterator::filePath() const
|
||||
{
|
||||
return d->currentFileInfo.filePath();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a QFileInfo for the current directory entry.
|
||||
|
||||
\sa filePath(), fileName()
|
||||
*/
|
||||
QFileInfo QDirIterator::fileInfo() const
|
||||
{
|
||||
return d->currentFileInfo;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the base directory of the iterator.
|
||||
*/
|
||||
QString QDirIterator::path() const
|
||||
{
|
||||
return d->dirEntry.filePath();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
55
src/corelib/io/qdirlisting.h
Normal file
55
src/corelib/io/qdirlisting.h
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef QDIRITERATOR_H
|
||||
#define QDIRITERATOR_H
|
||||
|
||||
#include <QtCore/qdir.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QDirIteratorPrivate;
|
||||
class Q_CORE_EXPORT QDirIterator
|
||||
{
|
||||
public:
|
||||
enum IteratorFlag {
|
||||
NoIteratorFlags = 0x0,
|
||||
FollowSymlinks = 0x1,
|
||||
Subdirectories = 0x2
|
||||
};
|
||||
Q_DECLARE_FLAGS(IteratorFlags, IteratorFlag)
|
||||
|
||||
QDirIterator(const QDir &dir, IteratorFlags flags = NoIteratorFlags);
|
||||
QDirIterator(const QString &path,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
QDirIterator(const QString &path,
|
||||
QDir::Filters filter,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
QDirIterator(const QString &path,
|
||||
const QStringList &nameFilters,
|
||||
QDir::Filters filters = QDir::NoFilter,
|
||||
IteratorFlags flags = NoIteratorFlags);
|
||||
|
||||
~QDirIterator();
|
||||
|
||||
QString next();
|
||||
QFileInfo nextFileInfo();
|
||||
bool hasNext() const;
|
||||
|
||||
QString fileName() const;
|
||||
QString filePath() const;
|
||||
QFileInfo fileInfo() const;
|
||||
QString path() const;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QDirIterator)
|
||||
|
||||
QScopedPointer<QDirIteratorPrivate> d;
|
||||
friend class QDir;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QDirIterator::IteratorFlags)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
45
tests/auto/corelib/io/qdirlisting/CMakeLists.txt
Normal file
45
tests/auto/corelib/io/qdirlisting/CMakeLists.txt
Normal file
@ -0,0 +1,45 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qdiriterator Test:
|
||||
#####################################################################
|
||||
|
||||
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(tst_qdiriterator LANGUAGES CXX)
|
||||
find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
|
||||
endif()
|
||||
|
||||
# Collect test data
|
||||
list(APPEND test_data "entrylist")
|
||||
|
||||
qt_internal_add_test(tst_qdiriterator
|
||||
SOURCES
|
||||
tst_qdiriterator.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
TESTDATA ${test_data}
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(qdiriterator_resource_files
|
||||
"entrylist/directory/dummy"
|
||||
"entrylist/file"
|
||||
)
|
||||
|
||||
qt_internal_add_resource(tst_qdiriterator "qdiriterator"
|
||||
PREFIX
|
||||
"/testdata/"
|
||||
FILES
|
||||
${qdiriterator_resource_files}
|
||||
)
|
||||
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_extend_target(tst_qdiriterator CONDITION CONFIG___contains___builtin_testdata
|
||||
DEFINES
|
||||
BUILTIN_TESTDATA
|
||||
)
|
0
tests/auto/corelib/io/qdirlisting/entrylist/file
Normal file
0
tests/auto/corelib/io/qdirlisting/entrylist/file
Normal file
633
tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
Normal file
633
tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
Normal file
@ -0,0 +1,633 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <qcoreapplication.h>
|
||||
#include <qdebug.h>
|
||||
#include <qdiriterator.h>
|
||||
#include <qfileinfo.h>
|
||||
#include <qstringlist.h>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
|
||||
#include <QtCore/private/qfsfileengine_p.h>
|
||||
|
||||
#if defined(Q_OS_VXWORKS)
|
||||
#define Q_NO_SYMLINKS
|
||||
#endif
|
||||
|
||||
#include "../../../../shared/filesystem.h"
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QStandardPaths>
|
||||
#endif
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
Q_DECLARE_METATYPE(QDirIterator::IteratorFlags)
|
||||
Q_DECLARE_METATYPE(QDir::Filters)
|
||||
|
||||
class tst_QDirIterator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool createFile(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
return file.open(QIODevice::WriteOnly);
|
||||
}
|
||||
|
||||
bool createLink(const QString &destination, const QString &linkName)
|
||||
{
|
||||
if (QFile::link(destination, linkName)) {
|
||||
createdFiles << linkName;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void iterateRelativeDirectory_data();
|
||||
void iterateRelativeDirectory();
|
||||
void iterateResource_data();
|
||||
void iterateResource();
|
||||
void stopLinkLoop();
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
void engineWithNoIterator();
|
||||
void testQFsFileEngineIterator_data() { iterateRelativeDirectory_data(); }
|
||||
void testQFsFileEngineIterator();
|
||||
#endif
|
||||
void absoluteFilePathsFromRelativeIteratorPath();
|
||||
void recurseWithFilters() const;
|
||||
void longPath();
|
||||
void dirorder();
|
||||
void relativePaths();
|
||||
#if defined(Q_OS_WIN)
|
||||
void uncPaths_data();
|
||||
void uncPaths();
|
||||
#endif
|
||||
#ifndef Q_OS_WIN
|
||||
void hiddenDirs_hiddenFiles();
|
||||
#endif
|
||||
|
||||
private:
|
||||
QTemporaryDir m_dataDir;
|
||||
};
|
||||
|
||||
void tst_QDirIterator::initTestCase()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
QString testdata_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
QString resourceSourcePath = QStringLiteral(":/testdata");
|
||||
QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QFileInfo fileInfo = it.nextFileInfo();
|
||||
|
||||
if (!fileInfo.isDir()) {
|
||||
QString destination = testdata_dir + QLatin1Char('/')
|
||||
+ fileInfo.filePath().mid(resourceSourcePath.length());
|
||||
QFileInfo destinationFileInfo(destination);
|
||||
if (!destinationFileInfo.exists()) {
|
||||
QDir().mkpath(destinationFileInfo.path());
|
||||
if (!QFile::copy(fileInfo.filePath(), destination))
|
||||
qWarning("Failed to copy %s", qPrintable(fileInfo.filePath()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
testdata_dir += QStringLiteral("/entrylist");
|
||||
#elif defined(BUILTIN_TESTDATA)
|
||||
m_dataDir = QEXTRACTTESTDATA("/testdata");
|
||||
QVERIFY2(!m_dataDir.isNull(), qPrintable("Could not extract test data"));
|
||||
QString testdata_dir = m_dataDir->path();
|
||||
#else
|
||||
|
||||
// chdir into testdata directory, then find testdata by relative paths.
|
||||
QString testdata_dir = m_dataDir.path();
|
||||
#endif
|
||||
|
||||
QVERIFY(!testdata_dir.isEmpty());
|
||||
// Must call QDir::setCurrent() here because all the tests that use relative
|
||||
// paths depend on that.
|
||||
QVERIFY2(QDir::setCurrent(testdata_dir), qPrintable("Could not chdir to " + testdata_dir));
|
||||
|
||||
createDirectory("entrylist");
|
||||
createDirectory("entrylist/directory");
|
||||
createFile("entrylist/file");
|
||||
createFile("entrylist/writable");
|
||||
createFile("entrylist/directory/dummy");
|
||||
|
||||
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)
|
||||
// ### 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
|
||||
|
||||
#if !defined(Q_OS_WIN)
|
||||
createDirectory("hiddenDirs_hiddenFiles");
|
||||
createFile("hiddenDirs_hiddenFiles/normalFile");
|
||||
createFile("hiddenDirs_hiddenFiles/.hiddenFile");
|
||||
createDirectory("hiddenDirs_hiddenFiles/normalDirectory");
|
||||
createDirectory("hiddenDirs_hiddenFiles/.hiddenDirectory");
|
||||
createFile("hiddenDirs_hiddenFiles/normalDirectory/normalFile");
|
||||
createFile("hiddenDirs_hiddenFiles/normalDirectory/.hiddenFile");
|
||||
createFile("hiddenDirs_hiddenFiles/.hiddenDirectory/normalFile");
|
||||
createFile("hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenFile");
|
||||
createDirectory("hiddenDirs_hiddenFiles/normalDirectory/normalDirectory");
|
||||
createDirectory("hiddenDirs_hiddenFiles/normalDirectory/.hiddenDirectory");
|
||||
createDirectory("hiddenDirs_hiddenFiles/.hiddenDirectory/normalDirectory");
|
||||
createDirectory("hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenDirectory");
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QDirIterator::iterateRelativeDirectory_data()
|
||||
{
|
||||
QTest::addColumn<QString>("dirName"); // relative from current path or abs
|
||||
QTest::addColumn<QDirIterator::IteratorFlags>("flags");
|
||||
QTest::addColumn<QDir::Filters>("filters");
|
||||
QTest::addColumn<QStringList>("nameFilters");
|
||||
QTest::addColumn<QStringList>("entries");
|
||||
|
||||
QTest::newRow("no flags")
|
||||
<< QString("entrylist") << QDirIterator::IteratorFlags{}
|
||||
<< QDir::Filters(QDir::NoFilter) << QStringList("*")
|
||||
<< QString(
|
||||
"entrylist/.,"
|
||||
"entrylist/..,"
|
||||
"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{}
|
||||
<< QDir::Filters(QDir::AllEntries | QDir::NoDot) << QStringList("*")
|
||||
<< QString(
|
||||
"entrylist/..,"
|
||||
"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{}
|
||||
<< QDir::Filters(QDir::AllEntries | QDir::NoDotDot) << QStringList("*")
|
||||
<< QString(
|
||||
"entrylist/.,"
|
||||
"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{}
|
||||
<< 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(
|
||||
"entrylist/.,"
|
||||
"entrylist/..,"
|
||||
"entrylist/directory/.,"
|
||||
"entrylist/directory/..,"
|
||||
"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{}
|
||||
<< QDir::Filters(QDir::NoFilter) << QStringList("*")
|
||||
<< QString("empty/.,empty/..").split(',');
|
||||
|
||||
QTest::newRow("empty, QDir::NoDotAndDotDot")
|
||||
<< QString("empty") << QDirIterator::IteratorFlags{}
|
||||
<< 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(const 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;
|
||||
for (const QString &item : entries)
|
||||
sortedEntries.append(QFileInfo(item).canonicalFilePath());
|
||||
sortedEntries.sort();
|
||||
|
||||
if (sortedEntries != list) {
|
||||
qDebug() << "ACTUAL: " << list;
|
||||
qDebug() << "EXPECTED:" << sortedEntries;
|
||||
}
|
||||
|
||||
QCOMPARE(list, sortedEntries);
|
||||
}
|
||||
|
||||
void tst_QDirIterator::iterateResource_data()
|
||||
{
|
||||
QTest::addColumn<QString>("dirName"); // relative from current path or abs
|
||||
QTest::addColumn<QDirIterator::IteratorFlags>("flags");
|
||||
QTest::addColumn<QDir::Filters>("filters");
|
||||
QTest::addColumn<QStringList>("nameFilters");
|
||||
QTest::addColumn<QStringList>("entries");
|
||||
|
||||
QTest::newRow("invalid") << QString::fromLatin1(":/testdata/burpaburpa") << QDirIterator::IteratorFlags{}
|
||||
<< QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*"))
|
||||
<< QStringList();
|
||||
QTest::newRow("qrc:/testdata") << u":/testdata/"_s << QDirIterator::IteratorFlags{}
|
||||
<< QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*"))
|
||||
<< QString::fromLatin1(":/testdata/entrylist").split(QLatin1String(","));
|
||||
QTest::newRow("qrc:/testdata/entrylist") << u":/testdata/entrylist"_s << QDirIterator::IteratorFlags{}
|
||||
<< QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*"))
|
||||
<< QString::fromLatin1(":/testdata/entrylist/directory,:/testdata/entrylist/file").split(QLatin1String(","));
|
||||
QTest::newRow("qrc:/testdata recursive") << u":/testdata"_s
|
||||
<< QDirIterator::IteratorFlags(QDirIterator::Subdirectories)
|
||||
<< QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*"))
|
||||
<< QString::fromLatin1(":/testdata/entrylist,:/testdata/entrylist/directory,:/testdata/entrylist/directory/dummy,:/testdata/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()) {
|
||||
const QString dir = it.next();
|
||||
if (!dir.startsWith(":/qt-project.org"))
|
||||
list << dir;
|
||||
}
|
||||
|
||||
list.sort();
|
||||
QStringList sortedEntries = entries;
|
||||
sortedEntries.sort();
|
||||
|
||||
if (sortedEntries != list) {
|
||||
qDebug() << "ACTUAL:" << list;
|
||||
qDebug() << "EXPECTED:" << sortedEntries;
|
||||
}
|
||||
|
||||
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.nextFileInfo();
|
||||
QVERIFY(max);
|
||||
|
||||
// The goal of this test is only to ensure that the test above don't malfunction
|
||||
}
|
||||
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
class EngineWithNoIterator : public QFSFileEngine
|
||||
{
|
||||
public:
|
||||
EngineWithNoIterator(const QString &fileName)
|
||||
: QFSFileEngine(fileName)
|
||||
{ }
|
||||
|
||||
QAbstractFileEngineIterator *beginEntryList(QDir::Filters, const QStringList &) override
|
||||
{ return 0; }
|
||||
};
|
||||
|
||||
class EngineWithNoIteratorHandler : public QAbstractFileEngineHandler
|
||||
{
|
||||
public:
|
||||
QAbstractFileEngine *create(const QString &fileName) const override
|
||||
{
|
||||
return new EngineWithNoIterator(fileName);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
void tst_QDirIterator::engineWithNoIterator()
|
||||
{
|
||||
EngineWithNoIteratorHandler handler;
|
||||
|
||||
QDir("entrylist").entryList();
|
||||
QVERIFY(true); // test that the above line doesn't crash
|
||||
}
|
||||
|
||||
class CustomEngineHandler : public QAbstractFileEngineHandler
|
||||
{
|
||||
public:
|
||||
QAbstractFileEngine *create(const QString &fileName) const override
|
||||
{
|
||||
// We want to test QFSFileEngine specifically, so force QDirIterator to use it
|
||||
// over the default QFileSystemEngine
|
||||
return new QFSFileEngine(fileName);
|
||||
}
|
||||
};
|
||||
|
||||
void tst_QDirIterator::testQFsFileEngineIterator()
|
||||
{
|
||||
QFETCH(QString, dirName);
|
||||
QFETCH(QStringList, nameFilters);
|
||||
QFETCH(QDir::Filters, filters);
|
||||
QFETCH(QDirIterator::IteratorFlags, flags);
|
||||
|
||||
if (dirName == u"empty")
|
||||
return; // This row isn't useful in this test
|
||||
|
||||
CustomEngineHandler handler;
|
||||
bool isEmpty = true;
|
||||
QDirIterator iter(dirName, nameFilters, filters, flags);
|
||||
while (iter.hasNext()) {
|
||||
const QFileInfo &fi = iter.nextFileInfo();
|
||||
if (fi.filePath().contains(u"entrylist"))
|
||||
isEmpty = false; // At least one entry in `entrylist` dir
|
||||
}
|
||||
QVERIFY(!isEmpty);
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QDirIterator::absoluteFilePathsFromRelativeIteratorPath()
|
||||
{
|
||||
QDirIterator it("entrylist/", QDir::NoDotAndDotDot);
|
||||
while (it.hasNext())
|
||||
QVERIFY(it.nextFileInfo().absoluteFilePath().contains("entrylist"));
|
||||
}
|
||||
|
||||
void tst_QDirIterator::recurseWithFilters() const
|
||||
{
|
||||
QStringList nameFilters;
|
||||
nameFilters.append("*.txt");
|
||||
|
||||
QDirIterator it("recursiveDirs/", nameFilters, QDir::Files,
|
||||
QDirIterator::Subdirectories);
|
||||
|
||||
QSet<QString> actualEntries;
|
||||
QSet<QString> expectedEntries;
|
||||
expectedEntries.insert(QString::fromLatin1("recursiveDirs/dir1/textFileB.txt"));
|
||||
expectedEntries.insert(QString::fromLatin1("recursiveDirs/textFileA.txt"));
|
||||
|
||||
QVERIFY(it.hasNext());
|
||||
actualEntries.insert(it.next());
|
||||
QVERIFY(it.hasNext());
|
||||
actualEntries.insert(it.next());
|
||||
QCOMPARE(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');
|
||||
}
|
||||
|
||||
QDirIterator it(dir.absolutePath(), QDir::NoDotAndDotDot|QDir::Dirs, QDirIterator::Subdirectories);
|
||||
int m = 0;
|
||||
while (it.hasNext()) {
|
||||
++m;
|
||||
it.nextFileInfo();
|
||||
}
|
||||
|
||||
QCOMPARE(n, m);
|
||||
|
||||
dirName.chop(1);
|
||||
while (dirName.size() > 0 && dir.exists(dirName) && dir.rmdir(dirName)) {
|
||||
dirName.chop(1);
|
||||
}
|
||||
dir.cdUp();
|
||||
dir.rmdir("longpaths");
|
||||
}
|
||||
|
||||
void tst_QDirIterator::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)
|
||||
void tst_QDirIterator::uncPaths_data()
|
||||
{
|
||||
QTest::addColumn<QString>("dirName");
|
||||
QTest::newRow("uncserver")
|
||||
<<QString("//" + QTest::uncServerName());
|
||||
QTest::newRow("uncserver/testshare")
|
||||
<<QString("//" + QTest::uncServerName() + "/testshare");
|
||||
QTest::newRow("uncserver/testshare/tmp")
|
||||
<<QString("//" + QTest::uncServerName() + "/testshare/tmp");
|
||||
}
|
||||
void tst_QDirIterator::uncPaths()
|
||||
{
|
||||
QFETCH(QString, dirName);
|
||||
QDirIterator iterator(dirName, QDir::AllEntries|QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
while(iterator.hasNext()) {
|
||||
iterator.next();
|
||||
QCOMPARE(iterator.filePath(), QDir::cleanPath(iterator.filePath()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
// In Unix it is easy to create hidden files, but in Windows it requires
|
||||
// a special call since hidden files need to be "marked" while in Unix
|
||||
// anything starting by a '.' is a hidden file.
|
||||
// For that reason this test is not run in Windows.
|
||||
void tst_QDirIterator::hiddenDirs_hiddenFiles()
|
||||
{
|
||||
// Only files
|
||||
{
|
||||
int matches = 0;
|
||||
int failures = 0;
|
||||
QDirIterator di("hiddenDirs_hiddenFiles", QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
while (di.hasNext()) {
|
||||
++matches;
|
||||
if (di.nextFileInfo().isDir())
|
||||
++failures; // search was only supposed to find files
|
||||
}
|
||||
QCOMPARE(matches, 6);
|
||||
QCOMPARE(failures, 0);
|
||||
}
|
||||
// Only directories
|
||||
{
|
||||
int matches = 0;
|
||||
int failures = 0;
|
||||
QDirIterator di("hiddenDirs_hiddenFiles", QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
while (di.hasNext()) {
|
||||
++matches;
|
||||
if (!di.nextFileInfo().isDir())
|
||||
++failures; // search was only supposed to find files
|
||||
}
|
||||
QCOMPARE(matches, 6);
|
||||
QCOMPARE(failures, 0);
|
||||
}
|
||||
}
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
QTEST_MAIN(tst_QDirIterator)
|
||||
|
||||
#include "tst_qdiriterator.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user