From e999c543a052a3301319329f78a8080c3df0669c Mon Sep 17 00:00:00 2001 From: David Faure Date: Wed, 30 Nov 2011 18:00:12 +0100 Subject: New class QTemporaryDir. As discussed on qt5-feedback / development lists. Change-Id: If1733369d12daa29054776ec2cbd78e63679768e Reviewed-by: Oswald Buddenhagen --- .../corelib/io/qtemporarydir/qtemporarydir.pro | 7 + .../corelib/io/qtemporarydir/tst_qtemporarydir.cpp | 471 +++++++++++++++++++++ 2 files changed, 478 insertions(+) create mode 100644 tests/auto/corelib/io/qtemporarydir/qtemporarydir.pro create mode 100644 tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp (limited to 'tests/auto/corelib/io/qtemporarydir') 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 +#include +#include +#include +#include +#include +#include +#ifdef Q_OS_WIN +# include +#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("constructorTemplate"); + QTest::addColumn("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 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::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("prefix"); + QTest::addColumn("suffix"); + QTest::addColumn("openResult"); + + QString unicode = QString::fromUtf8("\xc3\xa5\xc3\xa6\xc3\xb8"); + + QTest::newRow("") << 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") << QString() << unicode << true; + QTest::newRow("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" -- cgit v1.2.3