New class QTemporaryDir.

As discussed on qt5-feedback / development lists.

Change-Id: If1733369d12daa29054776ec2cbd78e63679768e
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
This commit is contained in:
David Faure 2011-11-30 18:00:12 +01:00 committed by Qt by Nokia
parent 4d696d53b0
commit e999c543a0
8 changed files with 879 additions and 3 deletions

View File

@ -0,0 +1,53 @@
/****************************************************************************
**
** 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 documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
{
//! [0]
// Within a function/method...
QTemporaryDir dir;
if (dir.isValid()) {
// dir.path() returns the unique directory path
}
// The QTemporaryDir destructor removes the temporary directory
// as it goes out of scope.
//! [0]
}

View File

@ -20,6 +20,7 @@ HEADERS += \
io/qprocess.h \
io/qprocess_p.h \
io/qtextstream.h \
io/qtemporarydir.h \
io/qtemporaryfile.h \
io/qresource_p.h \
io/qresource_iterator_p.h \
@ -54,6 +55,7 @@ SOURCES += \
io/qnoncontiguousbytedevice.cpp \
io/qprocess.cpp \
io/qtextstream.cpp \
io/qtemporarydir.cpp \
io/qtemporaryfile.cpp \
io/qresource.cpp \
io/qresource_iterator.cpp \

View File

@ -67,11 +67,11 @@ public:
static inline QStringList splitFilters(const QString &nameFilter, QChar sep = 0);
inline void setPath(const QString &path);
void setPath(const QString &path);
inline void clearFileLists();
void clearFileLists();
inline void resolveAbsoluteEntry() const;
void resolveAbsoluteEntry() const;
QStringList nameFilters;
QDir::SortFlags sort;

View File

@ -0,0 +1,258 @@
/****************************************************************************
**
** 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 QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtemporarydir.h"
#ifndef QT_NO_TEMPORARYFILE
#include "qdiriterator.h"
#include "qplatformdefs.h"
#include "private/qdir_p.h"
#include <QDebug>
#if defined(QT_BUILD_CORE_LIB)
#include "qcoreapplication.h"
#endif
#include <stdlib.h> // mkdtemp
#ifdef Q_OS_WIN
#include <windows.h>
#include <private/qfsfileengine_p.h>
#endif
QT_BEGIN_NAMESPACE
//************* QTemporaryDirPrivate
class QTemporaryDirPrivate
{
public:
QTemporaryDirPrivate();
~QTemporaryDirPrivate();
QString defaultTemplateName() const;
void create(const QString &templateName);
QString path;
bool autoRemove;
bool success;
};
QTemporaryDirPrivate::QTemporaryDirPrivate()
: autoRemove(true),
success(false)
{
}
QTemporaryDirPrivate::~QTemporaryDirPrivate()
{
}
QString QTemporaryDirPrivate::defaultTemplateName() const
{
QString baseName;
#if defined(QT_BUILD_CORE_LIB)
baseName = QCoreApplication::applicationName();
if (baseName.isEmpty())
#endif
baseName = QLatin1String("qt_temp");
return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String("-XXXXXX");
}
void QTemporaryDirPrivate::create(const QString &templateName)
{
#ifdef Q_OS_WIN
QString buffer = templateName;
// Windows' mktemp believes 26 temp files per process ought to be enough for everyone (!)
// Let's add a few random chars then, before the XXXXXX template.
for (int i = 0 ; i < 4 ; ++i)
buffer += QChar((qrand() & 0xffff) % (26) + 'A');
if (!buffer.endsWith(QLatin1String("XXXXXX")))
buffer += QLatin1String("XXXXXX");
QFileSystemEntry baseEntry(buffer);
QFileSystemEntry::NativePath basePath = baseEntry.nativeFilePath();
wchar_t* array = (wchar_t*)basePath.utf16();
if (_wmktemp(array) && ::CreateDirectory(array, 0)) {
success = true;
QFileSystemEntry entry(QString::fromWCharArray(array), QFileSystemEntry::FromNativePath());
path = entry.filePath();
}
#else
QByteArray buffer = QFile::encodeName(templateName);
if (!buffer.endsWith("XXXXXX"))
buffer += "XXXXXX";
if (mkdtemp(buffer.data())) { // modifies buffer
success = true;
path = QFile::decodeName(buffer.constData());
}
#endif
}
//************* QTemporaryDir
/*!
\class QTemporaryDir
\reentrant
\brief The QTemporaryDir class creates a unique directory for temporary use.
\ingroup io
QTemporaryDir is used to create unique temporary dirs safely.
The dir itself is created by the constructor. The name of the
temporary directory is guaranteed to be unique (i.e., you are
guaranteed to not overwrite an existing dir), and the directory will
subsequently be removed upon destruction of the QTemporaryDir
object. The directory name is either auto-generated, or created based
on a template, which is passed to QTemporaryDir's constructor.
Example:
\snippet doc/src/snippets/code/src_corelib_io_qtemporarydir.cpp 0
It is very important to test that the temporary directory could be
created, using isValid(). Do not use exists(), since a default-constructed
QDir represents the current directory, which exists.
The path to the temporary dir can be found by calling path().
A temporary directory will have some static part of the name and some
part that is calculated to be unique. The default path will be
determined from QCoreApplication::applicationName() (otherwise \c qt_temp) and will
be placed into the temporary path as returned by QDir::tempPath().
If you specify your own path, a relative path will not be placed in the
temporary directory by default, but be relative to the current working directory.
In all cases, a random string will be appended to the path in order to make it unique.
\sa QDir::tempPath(), QDir, QTemporaryFile
*/
QTemporaryDir::QTemporaryDir()
: d_ptr(new QTemporaryDirPrivate)
{
d_ptr->create(d_ptr->defaultTemplateName());
}
QTemporaryDir::QTemporaryDir(const QString &templateName)
: d_ptr(new QTemporaryDirPrivate)
{
if (templateName.isEmpty())
d_ptr->create(d_ptr->defaultTemplateName());
else
d_ptr->create(templateName);
}
/*!
Destroys the temporary directory object.
If auto remove mode was set, it will automatically delete the directory
including all its contents.
\sa autoRemove()
*/
QTemporaryDir::~QTemporaryDir()
{
if (d_ptr->success && d_ptr->autoRemove)
remove();
delete d_ptr;
}
/*!
Returns true if the QTemporaryDir was created successfully.
*/
bool QTemporaryDir::isValid() const
{
return d_ptr->success;
}
/*!
Returns the path to the temporary directory.
Empty if the QTemporaryDir could not be created.
*/
QString QTemporaryDir::path() const
{
return d_ptr->path;
}
/*!
Returns true if the QTemporaryDir is in auto remove
mode. Auto-remove mode will automatically delete the directory from
disk upon destruction. This makes it very easy to create your
QTemporaryDir object on the stack, fill it with files, do something with
the files, and finally on function return it will automatically clean up
after itself.
Auto-remove is on by default.
\sa setAutoRemove(), remove()
*/
bool QTemporaryDir::autoRemove() const
{
return d_ptr->autoRemove;
}
/*!
Sets the QTemporaryDir into auto-remove mode if \a b is true.
Auto-remove is on by default.
\sa autoRemove(), remove()
*/
void QTemporaryDir::setAutoRemove(bool b)
{
d_ptr->autoRemove = b;
}
/*!
Removes the temporary directory, including all its contents.
*/
bool QTemporaryDir::remove()
{
if (!d_ptr->success)
return false;
Q_ASSERT(!path().isEmpty());
Q_ASSERT(path() != QLatin1String("."));
return QDir(path()).removeRecursively();
}
QT_END_NAMESPACE
#endif // QT_NO_TEMPORARYFILE

View File

@ -0,0 +1,84 @@
/****************************************************************************
**
** 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 QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTEMPORARYDIR_H
#define QTEMPORARYDIR_H
#include <QtCore/qdir.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Core)
#ifndef QT_NO_TEMPORARYFILE
class QTemporaryDirPrivate;
class Q_CORE_EXPORT QTemporaryDir
{
public:
QTemporaryDir();
explicit QTemporaryDir(const QString &templateName);
~QTemporaryDir();
bool isValid() const;
bool autoRemove() const;
void setAutoRemove(bool b);
bool remove();
QString path() const;
private:
QTemporaryDirPrivate* const d_ptr;
Q_DISABLE_COPY(QTemporaryDir)
};
#endif // QT_NO_TEMPORARYFILE
QT_END_NAMESPACE
QT_END_HEADER
#endif // QTEMPORARYDIR_H

View File

@ -16,6 +16,7 @@ SUBDIRS=\
qresourceengine \
qsettings \
qstandardpaths \
qtemporarydir \
qtemporaryfile \
qtextstream \
qurl \

View File

@ -0,0 +1,7 @@
CONFIG += testcase
TARGET = tst_qtemporarydir
SOURCES += tst_qtemporarydir.cpp
QT = core testlib
CONFIG += parallel_test

View File

@ -0,0 +1,471 @@
/****************************************************************************
**
** 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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qcoreapplication.h>
#include <qstring.h>
#include <qtemporarydir.h>
#include <qfile.h>
#include <qdir.h>
#include <qset.h>
#ifdef Q_OS_WIN
# include <windows.h>
#endif
//TESTED_CLASS=QTemporaryDir
//TESTED_FILES=qtemporarydir.cpp
class tst_QTemporaryDir : public QObject
{
Q_OBJECT
public:
tst_QTemporaryDir();
virtual ~tst_QTemporaryDir();
public slots:
void init();
void cleanup();
void initTestCase();
void cleanupTestCase();
private slots:
void construction();
void fileTemplate();
void fileTemplate_data();
void getSetCheck();
void fileName();
void autoRemove();
void nonWritableCurrentDir();
void openOnRootDrives();
void stressTest();
void rename();
void autoRemoveAfterFailedRename();
void QTBUG_4796_data();
void QTBUG_4796();
public:
};
void tst_QTemporaryDir::initTestCase()
{
QVERIFY(QDir("test-XXXXXX").exists() || QDir().mkdir("test-XXXXXX"));
QCoreApplication::setApplicationName("tst_qtemporarydir");
}
void tst_QTemporaryDir::cleanupTestCase()
{
QVERIFY(QDir().rmdir("test-XXXXXX"));
}
void tst_QTemporaryDir::construction()
{
QTemporaryDir dir;
QString tmp = QDir::tempPath();
QCOMPARE(dir.path().left(tmp.size()), tmp);
QVERIFY(dir.path().contains("tst_qtemporarydir"));
QVERIFY(QFileInfo(dir.path()).isDir());
}
// Testing get/set functions
void tst_QTemporaryDir::getSetCheck()
{
QTemporaryDir obj1;
// bool QTemporaryDir::autoRemove()
// void QTemporaryDir::setAutoRemove(bool)
obj1.setAutoRemove(false);
QCOMPARE(false, obj1.autoRemove());
obj1.setAutoRemove(true);
QCOMPARE(true, obj1.autoRemove());
}
tst_QTemporaryDir::tst_QTemporaryDir()
{
}
tst_QTemporaryDir::~tst_QTemporaryDir()
{
}
void tst_QTemporaryDir::init()
{
}
void tst_QTemporaryDir::cleanup()
{
}
void tst_QTemporaryDir::fileTemplate_data()
{
QTest::addColumn<QString>("constructorTemplate");
QTest::addColumn<QString>("prefix");
QTest::newRow("constructor default") << "" << "tst_qtemporarydir-";
QTest::newRow("constructor with xxx sufix") << "qt_XXXXXXxxx" << "qt_XXXXXXxxx";
QTest::newRow("constructor with xXx sufix") << "qt_XXXXXXxXx" << "qt_XXXXXXxXx";
QTest::newRow("constructor with no suffix") << "qt_XXXXXX" << "qt_";
QTest::newRow("constructor with >6 X's, no suffix") << "qt_XXXXXXXXXX" << "qt_XXXX";
QTest::newRow("constructor with XXXX suffix") << "qt_XXXXXX_XXXX" << "qt_";
QTest::newRow("constructor with XXXX prefix") << "qt_XXXX" << "qt_XXXX";
QTest::newRow("constructor with XXXXX prefix") << "qt_XXXXX" << "qt_XXXXX";
}
void tst_QTemporaryDir::fileTemplate()
{
QFETCH(QString, constructorTemplate);
QFETCH(QString, prefix);
QTemporaryDir tempDir(constructorTemplate);
QVERIFY(tempDir.isValid());
QString dirName = QDir(tempDir.path()).dirName();
if (prefix.length())
QCOMPARE(dirName.left(prefix.length()), prefix);
}
/*
This tests whether the temporary dir really gets placed in QDir::tempPath
*/
void tst_QTemporaryDir::fileName()
{
// Get QDir::tempPath and make an absolute path.
QString tempPath = QDir::tempPath();
QString absoluteTempPath = QDir(tempPath).absolutePath();
QTemporaryDir dir;
dir.setAutoRemove(true);
QString fileName = dir.path();
QVERIFY2(fileName.contains("/tst_qtemporarydir-"), qPrintable(fileName));
QVERIFY(QFile::exists(fileName));
// Get path to the temp dir, without the file name.
QString absoluteFilePath = QFileInfo(fileName).absolutePath();
#if defined(Q_OS_WIN)
absoluteFilePath = absoluteFilePath.toLower();
absoluteTempPath = absoluteTempPath.toLower();
#endif
QCOMPARE(absoluteFilePath, absoluteTempPath);
}
void tst_QTemporaryDir::autoRemove()
{
// Test auto remove
QString dirName;
{
QTemporaryDir dir("tempXXXXXX");
dir.setAutoRemove(true);
QVERIFY(dir.isValid());
dirName = dir.path();
}
#ifdef Q_OS_WIN
// Windows seems unreliable here: sometimes it says the directory still exists,
// immediately after we deleted it.
QTRY_VERIFY(!QFile::exists(dirName));
#else
QVERIFY(!QFile::exists(dirName));
#endif
// Test if disabling auto remove works.
{
QTemporaryDir dir("tempXXXXXX");
dir.setAutoRemove(false);
QVERIFY(dir.isValid());
dirName = dir.path();
}
QVERIFY(QFile::exists(dirName));
QVERIFY(QDir().rmdir(dirName));
QVERIFY(!QFile::exists(dirName));
// Do not explicitly call setAutoRemove (tests if it really is the default as documented)
{
QTemporaryDir dir("tempXXXXXX");
QVERIFY(dir.isValid());
dirName = dir.path();
}
#ifdef Q_OS_WIN
QTRY_VERIFY(!QFile::exists(dirName));
#else
QVERIFY(!QFile::exists(dirName));
#endif
// Test autoremove with files and subdirs in the temp dir
{
QTemporaryDir tempDir("tempXXXXXX");
QVERIFY(tempDir.isValid());
dirName = tempDir.path();
QDir dir(dirName);
QVERIFY(dir.mkdir(QString::fromLatin1("dir1")));
QVERIFY(dir.mkdir(QString::fromLatin1("dir2")));
QVERIFY(dir.mkdir(QString::fromLatin1("dir2/nested")));
QFile file(dirName + "/dir1/file");
QVERIFY(file.open(QIODevice::WriteOnly));
QCOMPARE(file.write("Hello"), 5LL);
}
#ifdef Q_OS_WIN
QTRY_VERIFY(!QFile::exists(dirName));
#else
QVERIFY(!QFile::exists(dirName));
#endif
}
void tst_QTemporaryDir::nonWritableCurrentDir()
{
#ifdef Q_OS_UNIX
QString cwd = QDir::currentPath();
QDir::setCurrent("/");
// QTemporaryDir("tempXXXXXX") is probably a bad idea in any app
// where the current dir could anything...
QString fileName;
QTemporaryDir dir("tempXXXXXX");
dir.setAutoRemove(true);
QVERIFY(!dir.isValid());
fileName = dir.path();
QDir::setCurrent(cwd);
#endif
}
void tst_QTemporaryDir::openOnRootDrives()
{
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
unsigned int lastErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
#endif
// If it's possible to create a dir in the root directory, it
// must be possible to create a temp dir there too.
foreach (const QFileInfo &driveInfo, QDir::drives()) {
QFile testFile(driveInfo.filePath() + "XXXXXX.txt");
if (testFile.open(QIODevice::ReadWrite)) {
testFile.remove();
QTemporaryDir dir(driveInfo.filePath() + "XXXXXX.txt");
dir.setAutoRemove(true);
QVERIFY(dir.isValid());
}
}
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
SetErrorMode(lastErrorMode);
#endif
}
void tst_QTemporaryDir::stressTest()
{
const int iterations = 1000;
QSet<QString> names;
for (int i = 0; i < iterations; ++i) {
QTemporaryDir dir;
dir.setAutoRemove(false);
QVERIFY2(dir.isValid(), qPrintable(QString::number(i)));
QVERIFY(!names.contains(dir.path()));
names.insert(dir.path());
}
for (QSet<QString>::const_iterator it = names.constBegin(); it != names.constEnd(); ++it)
QDir(*it).removeRecursively();
}
void tst_QTemporaryDir::rename()
{
// This test checks what happens if the temporary dir is renamed.
// Then the autodelete feature can't possibly find it.
QDir dir;
QVERIFY(!dir.exists("temporary-dir.renamed"));
QString tempname;
{
QTemporaryDir tempDir(dir.filePath("temporary-dir.XXXXXX"));
QVERIFY(tempDir.isValid());
tempname = tempDir.path();
QVERIFY(QDir().rename(tempname, "temporary-dir.renamed"));
QVERIFY(!QDir(tempname).exists());
dir.setPath("temporary-dir.renamed");
QCOMPARE(dir.path(), QString("temporary-dir.renamed"));
QVERIFY(dir.exists());
}
// Auto-delete couldn't find it
QVERIFY(dir.exists());
// Clean up by hand
QVERIFY(dir.removeRecursively());
QVERIFY(!dir.exists());
}
void tst_QTemporaryDir::autoRemoveAfterFailedRename()
{
struct CleanOnReturn
{
~CleanOnReturn()
{
if (!tempName.isEmpty())
QVERIFY(QDir(tempName).removeRecursively());
}
void reset()
{
tempName.clear();
}
QString tempName;
};
CleanOnReturn cleaner;
{
QTemporaryDir dir;
QVERIFY(dir.isValid());
cleaner.tempName = dir.path();
QVERIFY(QFile::exists(cleaner.tempName));
QVERIFY(!QFileInfo("i-do-not-exist").isDir());
QVERIFY(!QDir().rename(cleaner.tempName, "i-do-not-exist/dir.txt"));
QVERIFY(QFile::exists(cleaner.tempName));
}
QVERIFY(!QFile::exists(cleaner.tempName));
cleaner.reset();
}
void tst_QTemporaryDir::QTBUG_4796_data()
{
QTest::addColumn<QString>("prefix");
QTest::addColumn<QString>("suffix");
QTest::addColumn<bool>("openResult");
QString unicode = QString::fromUtf8("\xc3\xa5\xc3\xa6\xc3\xb8");
QTest::newRow("<empty>") << QString() << QString() << true;
QTest::newRow(".") << QString(".") << QString() << true;
QTest::newRow("..") << QString("..") << QString() << true;
QTest::newRow("blaXXXXXX") << QString("bla") << QString() << true;
QTest::newRow("does-not-exist/qt_temp.XXXXXX") << QString("does-not-exist/qt_temp") << QString() << false;
QTest::newRow("XXXXXX<unicode>") << QString() << unicode << true;
QTest::newRow("<unicode>XXXXXX") << unicode << QString() << true;
}
void tst_QTemporaryDir::QTBUG_4796()
{
QVERIFY(QDir("test-XXXXXX").exists());
struct CleanOnReturn
{
~CleanOnReturn()
{
foreach (const QString &tempName, tempNames)
QVERIFY(QDir(tempName).removeRecursively());
}
void reset()
{
tempNames.clear();
}
QStringList tempNames;
};
CleanOnReturn cleaner;
QFETCH(QString, prefix);
QFETCH(QString, suffix);
QFETCH(bool, openResult);
{
QString fileTemplate1 = prefix + QString("XX") + suffix;
QString fileTemplate2 = prefix + QString("XXXX") + suffix;
QString fileTemplate3 = prefix + QString("XXXXXX") + suffix;
QString fileTemplate4 = prefix + QString("XXXXXXXX") + suffix;
QTemporaryDir dir1(fileTemplate1);
QTemporaryDir dir2(fileTemplate2);
QTemporaryDir dir3(fileTemplate3);
QTemporaryDir dir4(fileTemplate4);
QTemporaryDir dir5("test-XXXXXX/" + fileTemplate1);
QTemporaryDir dir6("test-XXXXXX/" + fileTemplate3);
QCOMPARE(dir1.isValid(), openResult);
QCOMPARE(dir2.isValid(), openResult);
QCOMPARE(dir3.isValid(), openResult);
QCOMPARE(dir4.isValid(), openResult);
QCOMPARE(dir5.isValid(), openResult);
QCOMPARE(dir6.isValid(), openResult);
// make sure the dir exists under the *correct* name
if (openResult) {
cleaner.tempNames << dir1.path()
<< dir2.path()
<< dir3.path()
<< dir4.path()
<< dir5.path()
<< dir6.path();
QDir currentDir;
QString fileName1 = currentDir.relativeFilePath(dir1.path());
QString fileName2 = currentDir.relativeFilePath(dir2.path());
QString fileName3 = currentDir.relativeFilePath(dir3.path());
QString fileName4 = currentDir.relativeFilePath(dir4.path());
QString fileName5 = currentDir.relativeFilePath(dir5.path());
QString fileName6 = currentDir.relativeFilePath(dir6.path());
QVERIFY(fileName1.startsWith(fileTemplate1));
QVERIFY(fileName2.startsWith(fileTemplate2));
QVERIFY(fileName5.startsWith("test-XXXXXX/" + fileTemplate1));
QVERIFY(fileName6.startsWith("test-XXXXXX/" + prefix));
if (!prefix.isEmpty()) {
QVERIFY(fileName3.startsWith(prefix));
QVERIFY(fileName4.startsWith(prefix));
}
}
}
#ifdef Q_OS_WIN
QTest::qWait(20);
#endif
foreach (const QString &tempName, cleaner.tempNames)
QVERIFY2(!QFile::exists(tempName), qPrintable(tempName));
cleaner.reset();
}
QTEST_MAIN(tst_QTemporaryDir)
#include "tst_qtemporarydir.moc"