summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Faure <faure@kde.org>2011-11-30 18:00:12 +0100
committerQt by Nokia <qt-info@nokia.com>2011-12-02 21:04:34 +0100
commite999c543a052a3301319329f78a8080c3df0669c (patch)
tree61f78ad131bfd32c85f639396f1bada36446c03b
parent4d696d53b074dafc1ecfc1d9cb6fd041464e1a75 (diff)
New class QTemporaryDir.
As discussed on qt5-feedback / development lists. Change-Id: If1733369d12daa29054776ec2cbd78e63679768e Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
-rw-r--r--doc/src/snippets/code/src_corelib_io_qtemporarydir.cpp53
-rw-r--r--src/corelib/io/io.pri2
-rw-r--r--src/corelib/io/qdir_p.h6
-rw-r--r--src/corelib/io/qtemporarydir.cpp258
-rw-r--r--src/corelib/io/qtemporarydir.h84
-rw-r--r--tests/auto/corelib/io/io.pro1
-rw-r--r--tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro7
-rw-r--r--tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp471
8 files changed, 879 insertions, 3 deletions
diff --git a/doc/src/snippets/code/src_corelib_io_qtemporarydir.cpp b/doc/src/snippets/code/src_corelib_io_qtemporarydir.cpp
new file mode 100644
index 0000000000..4cdc54a6c4
--- /dev/null
+++ b/doc/src/snippets/code/src_corelib_io_qtemporarydir.cpp
@@ -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]
+}
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index 4fa5ed035e..ef11621679 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -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 \
diff --git a/src/corelib/io/qdir_p.h b/src/corelib/io/qdir_p.h
index 7644a0391e..a34427a716 100644
--- a/src/corelib/io/qdir_p.h
+++ b/src/corelib/io/qdir_p.h
@@ -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;
diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp
new file mode 100644
index 0000000000..c3a41fdd4c
--- /dev/null
+++ b/src/corelib/io/qtemporarydir.cpp
@@ -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
diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h
new file mode 100644
index 0000000000..96dc18d952
--- /dev/null
+++ b/src/corelib/io/qtemporarydir.h
@@ -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
diff --git a/tests/auto/corelib/io/io.pro b/tests/auto/corelib/io/io.pro
index 3c68e0a6a7..e044eda1ca 100644
--- a/tests/auto/corelib/io/io.pro
+++ b/tests/auto/corelib/io/io.pro
@@ -16,6 +16,7 @@ SUBDIRS=\
qresourceengine \
qsettings \
qstandardpaths \
+ qtemporarydir \
qtemporaryfile \
qtextstream \
qurl \
diff --git a/tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro b/tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro
new file mode 100644
index 0000000000..b34d2cca07
--- /dev/null
+++ b/tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro
@@ -0,0 +1,7 @@
+CONFIG += testcase
+TARGET = tst_qtemporarydir
+SOURCES += tst_qtemporarydir.cpp
+
+QT = core testlib
+
+CONFIG += parallel_test
diff --git a/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp
new file mode 100644
index 0000000000..e1ead8c9c0
--- /dev/null
+++ b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp
@@ -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"