summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/io/qfile
diff options
context:
space:
mode:
authorHolger Ihrig <holger.ihrig@nokia.com>2011-08-24 12:53:32 +0200
committerHolger Ihrig <holger.ihrig@nokia.com>2011-08-31 10:08:38 +0200
commit012ba8c0e5270f962dbc891039c32f49d31c565b (patch)
tree499a88b02862551708eb0f2c0f366afa8b998054 /tests/auto/corelib/io/qfile
parenta7d682dd9c9271d137d5aa73a9192a812492a596 (diff)
Moving relevant tests to corelib/io
Marked Test for qdiriterator as insignificant. See QTBUG-21160 Marked Test for qresourceengine as insignificant. See QTBUG-21159 Task-number: QTBUG-21066 Change-Id: I72848a651ff3e7aff1d6105dd49124e4ed070a44 Reviewed-on: http://codereview.qt.nokia.com/3577 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com> Reviewed-by: Jason McDonald <jason.mcdonald@nokia.com>
Diffstat (limited to 'tests/auto/corelib/io/qfile')
-rw-r--r--tests/auto/corelib/io/qfile/.gitattributes2
-rw-r--r--tests/auto/corelib/io/qfile/.gitignore8
-rw-r--r--tests/auto/corelib/io/qfile/copy-fallback.qrc5
-rw-r--r--tests/auto/corelib/io/qfile/dosfile.txt14
-rw-r--r--tests/auto/corelib/io/qfile/forCopying.txt1
-rw-r--r--tests/auto/corelib/io/qfile/forRenaming.txt7
-rw-r--r--tests/auto/corelib/io/qfile/largefile/largefile.pro8
-rw-r--r--tests/auto/corelib/io/qfile/largefile/tst_largefile.cpp538
-rw-r--r--tests/auto/corelib/io/qfile/noendofline.txt3
-rw-r--r--tests/auto/corelib/io/qfile/qfile.pro10
-rw-r--r--tests/auto/corelib/io/qfile/qfile.qrc5
-rw-r--r--tests/auto/corelib/io/qfile/rename-fallback.qrc5
-rw-r--r--tests/auto/corelib/io/qfile/resources/file1.ext11
-rw-r--r--tests/auto/corelib/io/qfile/stdinprocess/main.cpp72
-rw-r--r--tests/auto/corelib/io/qfile/stdinprocess/stdinprocess.pro6
-rw-r--r--tests/auto/corelib/io/qfile/test/test.pro44
-rw-r--r--tests/auto/corelib/io/qfile/testfile.txt6
-rw-r--r--tests/auto/corelib/io/qfile/testlog.txt144
-rw-r--r--tests/auto/corelib/io/qfile/tst_qfile.cpp3406
-rw-r--r--tests/auto/corelib/io/qfile/two.dots.file1
20 files changed, 4286 insertions, 0 deletions
diff --git a/tests/auto/corelib/io/qfile/.gitattributes b/tests/auto/corelib/io/qfile/.gitattributes
new file mode 100644
index 0000000000..3be66dc5eb
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/.gitattributes
@@ -0,0 +1,2 @@
+dosfile.txt -crlf
+testfile.txt -crlf \ No newline at end of file
diff --git a/tests/auto/corelib/io/qfile/.gitignore b/tests/auto/corelib/io/qfile/.gitignore
new file mode 100644
index 0000000000..c508239722
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/.gitignore
@@ -0,0 +1,8 @@
+tst_qfile
+stdinprocess/stdinprocess
+stdinprocess/stdinprocess.exe
+readonlyfile
+newfile.txt
+appendfile.txt
+oldfile.txt
+simplefile.txt
diff --git a/tests/auto/corelib/io/qfile/copy-fallback.qrc b/tests/auto/corelib/io/qfile/copy-fallback.qrc
new file mode 100644
index 0000000000..864491f326
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/copy-fallback.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>copy-fallback.qrc</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/corelib/io/qfile/dosfile.txt b/tests/auto/corelib/io/qfile/dosfile.txt
new file mode 100644
index 0000000000..47205062e1
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/dosfile.txt
@@ -0,0 +1,14 @@
+/dev/system/root / reiserfs acl,user_xattr 1 1
+/dev/sda1 /boot ext3 acl,user_xattr 1 2
+/dev/system/home /home reiserfs acl,user_xattr 1 2
+/dev/system/temp /tmp reiserfs acl,user_xattr 1 2
+/dev/sda2 swap swap pri=42 0 0
+devpts /dev/pts devpts mode=0620,gid=5 0 0
+proc /proc proc defaults 0 0
+usbfs /proc/bus/usb usbfs noauto 0 0
+sysfs /sys sysfs noauto 0 0
+/dev/dvd /media/dvd subfs noauto,fs=cdfss,ro,procuid,nosuid,nodev,exec,iocharset=utf8 0 0
+/dev/fd0 /media/floppy subfs noauto,fs=floppyfss,procuid,nodev,nosuid,sync 0 0
+/dev/sdb2 /media/ipod subfs noauto,rw,noexec,nosuid,nodev,sync,procuid,user,iocharset=utf8 1 2
+/dev/sdc1 /media/usbkey vfat rw,nosuid,nodev,sync,procuid,user 1 2
+
diff --git a/tests/auto/corelib/io/qfile/forCopying.txt b/tests/auto/corelib/io/qfile/forCopying.txt
new file mode 100644
index 0000000000..d4143d5958
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/forCopying.txt
@@ -0,0 +1 @@
+A basic file for copying.
diff --git a/tests/auto/corelib/io/qfile/forRenaming.txt b/tests/auto/corelib/io/qfile/forRenaming.txt
new file mode 100644
index 0000000000..7032162406
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/forRenaming.txt
@@ -0,0 +1,7 @@
+----------------------------------------------------------
+DO NOT CHANGE ANY CONTENT OR ACCESS RIGHTS OF THIS FILE!!!
+----------------------------------------------------------
+
+This file is larger than QFile::rename()'s buffer, which is 4096 bytes. This means it is more than what is returned in its call to read().
+
+112345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890234567890
diff --git a/tests/auto/corelib/io/qfile/largefile/largefile.pro b/tests/auto/corelib/io/qfile/largefile/largefile.pro
new file mode 100644
index 0000000000..6407cb6b3e
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/largefile/largefile.pro
@@ -0,0 +1,8 @@
+load(qttest_p4)
+
+QT = core
+SOURCES += tst_largefile.cpp
+
+wince*: SOURCES += $$QT_SOURCE_TREE/src/corelib/kernel/qfunctions_wince.cpp
+
+CONFIG += parallel_test
diff --git a/tests/auto/corelib/io/qfile/largefile/tst_largefile.cpp b/tests/auto/corelib/io/qfile/largefile/tst_largefile.cpp
new file mode 100644
index 0000000000..bf6cc688ba
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/largefile/tst_largefile.cpp
@@ -0,0 +1,538 @@
+/****************************************************************************
+**
+** 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 <QTest>
+
+#include <QtAlgorithms>
+#include <QFile>
+#include <QFileInfo>
+#include <qplatformdefs.h>
+
+#include <QDebug>
+
+#include <cstdlib>
+#include <cstdio>
+
+#ifdef Q_OS_WIN
+
+#include <windows.h>
+
+#ifndef Q_OS_WINCE
+#include <io.h>
+#endif
+
+#ifndef FSCTL_SET_SPARSE
+// MinGW doesn't define this.
+#define FSCTL_SET_SPARSE (0x900C4)
+#endif
+
+#endif // Q_OS_WIN
+
+class tst_LargeFile
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_LargeFile()
+ : blockSize(1 << 12)
+ , maxSizeBits()
+ , fd_(-1)
+ , stream_(0)
+ {
+ #if defined(QT_LARGEFILE_SUPPORT) && !defined(Q_OS_MAC)
+ maxSizeBits = 36; // 64 GiB
+ #elif defined(Q_OS_MAC)
+ // HFS+ does not support sparse files, so we limit file size for the test
+ // on Mac OS.
+ maxSizeBits = 32; // 4 GiB
+ #else
+ maxSizeBits = 24; // 16 MiB
+ #endif
+ }
+
+private:
+ void sparseFileData();
+ QByteArray const &getDataBlock(int index, qint64 position);
+
+private slots:
+ // The LargeFile test case was designed to be run in order as a single unit
+
+ void initTestCase();
+ void cleanupTestCase();
+
+ void init();
+ void cleanup();
+
+ // Create and fill large file
+ void createSparseFile();
+ void fillFileSparsely();
+ void closeSparseFile();
+
+ // Verify file was created
+ void fileCreated();
+
+ // Positioning in large files
+ void filePositioning();
+ void fdPositioning();
+ void streamPositioning();
+
+ // Read data from file
+ void openFileForReading();
+ void readFile();
+
+ // Map/unmap large file
+ void mapFile();
+ void mapOffsetOverflow();
+
+ void closeFile() { largeFile.close(); }
+
+ // Test data
+ void fillFileSparsely_data() { sparseFileData(); }
+ void filePositioning_data() { sparseFileData(); }
+ void fdPositioning_data() { sparseFileData(); }
+ void streamPositioning_data() { sparseFileData(); }
+ void readFile_data() { sparseFileData(); }
+ void mapFile_data() { sparseFileData(); }
+
+private:
+ const int blockSize;
+ int maxSizeBits;
+
+ QFile largeFile;
+
+ QVector<QByteArray> generatedBlocks;
+
+ int fd_;
+ FILE *stream_;
+};
+
+/*
+ Convenience function to hide reinterpret_cast when copying a POD directly
+ into a QByteArray.
+ */
+template <class T>
+static inline void appendRaw(QByteArray &array, T data)
+{
+ array.append(reinterpret_cast<char *>(&data), sizeof(T));
+}
+
+/*
+ Pad array with filler up to size. On return, array.size() returns size.
+ */
+static inline void topUpWith(QByteArray &array, QByteArray filler, int size)
+{
+ for (int i = (size - array.size()) / filler.size(); i > 0; --i)
+ array.append(filler);
+
+ if (array.size() < size) {
+ array.append(filler.left(size - array.size()));
+ }
+}
+
+/*
+ Generate a unique data block containing identifiable data. Unaligned,
+ overlapping and partial blocks should not compare equal.
+ */
+static inline QByteArray generateDataBlock(int blockSize, QString text, qint64 userBits = -1)
+{
+ QByteArray block;
+ block.reserve(blockSize);
+
+ // Use of counter and randomBits means content of block will be dependent
+ // on the generation order. For (file-)systems that do not support sparse
+ // files, these can be removed so the test file can be reused and doesn't
+ // have to be generated for every run.
+
+ static qint64 counter = 0;
+
+ qint64 randomBits = ((qint64)qrand() << 32)
+ | ((qint64)qrand() & 0x00000000ffffffff);
+
+ appendRaw(block, randomBits);
+ appendRaw(block, userBits);
+ appendRaw(block, counter);
+ appendRaw(block, (qint32)0xdeadbeef);
+ appendRaw(block, blockSize);
+
+ QByteArray userContent = text.toUtf8();
+ appendRaw(block, userContent.size());
+ block.append(userContent);
+ appendRaw(block, (qint64)0);
+
+ // size, so far
+ appendRaw(block, block.size());
+
+ QByteArray filler("0123456789");
+ block.append(filler.right(10 - block.size() % 10));
+ topUpWith(block, filler, blockSize - 3 * sizeof(qint64));
+
+ appendRaw(block, counter);
+ appendRaw(block, userBits);
+ appendRaw(block, randomBits);
+
+ ++counter;
+ return block;
+}
+
+/*
+ Generates data blocks the first time they are requested. Keeps copies for reuse.
+ */
+QByteArray const &tst_LargeFile::getDataBlock(int index, qint64 position)
+{
+ if (index >= generatedBlocks.size())
+ generatedBlocks.resize(index + 1);
+
+ if (generatedBlocks[index].isNull()) {
+ QString text = QString("Current %1-byte block (index = %2) "
+ "starts %3 bytes into the file '%4'.")
+ .arg(blockSize)
+ .arg(index)
+ .arg(position)
+ .arg("qt_largefile.tmp");
+
+ generatedBlocks[index] = generateDataBlock(blockSize, text, (qint64)1 << index);
+ }
+
+ return generatedBlocks[index];
+}
+
+void tst_LargeFile::initTestCase()
+{
+ QFile file("qt_largefile.tmp");
+ QVERIFY( !file.exists() || file.remove() );
+}
+
+void tst_LargeFile::cleanupTestCase()
+{
+ if (largeFile.isOpen())
+ largeFile.close();
+
+ QFile file("qt_largefile.tmp");
+ QVERIFY( !file.exists() || file.remove() );
+}
+
+void tst_LargeFile::init()
+{
+ fd_ = -1;
+ stream_ = 0;
+}
+
+void tst_LargeFile::cleanup()
+{
+ if (-1 != fd_)
+ QT_CLOSE(fd_);
+ if (stream_)
+ ::fclose(stream_);
+}
+
+void tst_LargeFile::sparseFileData()
+{
+ QTest::addColumn<int>("index");
+ QTest::addColumn<qint64>("position");
+ QTest::addColumn<QByteArray>("block");
+
+ QTest::newRow(QString("block[%1] @%2)")
+ .arg(0).arg(0)
+ .toLocal8Bit().constData())
+ << 0 << (qint64)0 << getDataBlock(0, 0);
+
+ // While on Linux sparse files scale well, on Windows, testing at every
+ // power of 2 leads to very large files. i += 4 gives us a good coverage
+ // without taxing too much on resources.
+ for (int index = 12; index <= maxSizeBits; index += 4) {
+ qint64 position = (qint64)1 << index;
+ QByteArray block = getDataBlock(index, position);
+
+ QTest::newRow(
+ QString("block[%1] @%2)")
+ .arg(index).arg(position)
+ .toLocal8Bit().constData())
+ << index << position << block;
+ }
+}
+
+void tst_LargeFile::createSparseFile()
+{
+#if defined(Q_OS_WIN32)
+ // On Windows platforms, we must explicitly set the file to be sparse,
+ // so disk space is not allocated for the full file when writing to it.
+ HANDLE handle = ::CreateFileA("qt_largefile.tmp",
+ GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
+ QVERIFY( INVALID_HANDLE_VALUE != handle );
+
+ DWORD bytes;
+ if (!::DeviceIoControl(handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0,
+ &bytes, NULL)) {
+ QWARN("Unable to set test file as sparse. "
+ "Limiting test file to 16MiB.");
+ maxSizeBits = 24;
+ }
+
+ int fd = ::_open_osfhandle((intptr_t)handle, 0);
+ QVERIFY( -1 != fd );
+ QVERIFY( largeFile.open(fd, QIODevice::WriteOnly | QIODevice::Unbuffered) );
+#else // !Q_OS_WIN32
+ largeFile.setFileName("qt_largefile.tmp");
+ QVERIFY( largeFile.open(QIODevice::WriteOnly | QIODevice::Unbuffered) );
+#endif
+}
+
+void tst_LargeFile::closeSparseFile()
+{
+#if defined(Q_OS_WIN32)
+ int fd = largeFile.handle();
+#endif
+
+ largeFile.close();
+
+#if defined(Q_OS_WIN32)
+ if (-1 != fd)
+ ::_close(fd);
+#endif
+}
+
+void tst_LargeFile::fillFileSparsely()
+{
+ QFETCH( qint64, position );
+ QFETCH( QByteArray, block );
+ QCOMPARE( block.size(), blockSize );
+
+ static int lastKnownGoodIndex = 0;
+ struct ScopeGuard {
+ ScopeGuard(tst_LargeFile* test)
+ : this_(test)
+ , failed(true)
+ {
+ QFETCH( int, index );
+ index_ = index;
+ }
+
+ ~ScopeGuard()
+ {
+ if (failed) {
+ this_->maxSizeBits = lastKnownGoodIndex;
+ QWARN( qPrintable(
+ QString("QFile::error %1: '%2'. Maximum size bits reset to %3.")
+ .arg(this_->largeFile.error())
+ .arg(this_->largeFile.errorString())
+ .arg(this_->maxSizeBits)) );
+ } else
+ lastKnownGoodIndex = qMax<int>(index_, lastKnownGoodIndex);
+ }
+
+ private:
+ tst_LargeFile * const this_;
+ int index_;
+
+ public:
+ bool failed;
+ };
+
+ ScopeGuard resetMaxSizeBitsOnFailure(this);
+
+ QVERIFY( largeFile.seek(position) );
+ QCOMPARE( largeFile.pos(), position );
+
+ QCOMPARE( largeFile.write(block), (qint64)blockSize );
+ QCOMPARE( largeFile.pos(), position + blockSize );
+ QVERIFY( largeFile.flush() );
+
+ resetMaxSizeBitsOnFailure.failed = false;
+}
+
+void tst_LargeFile::fileCreated()
+{
+ QFileInfo info("qt_largefile.tmp");
+
+ QVERIFY( info.exists() );
+ QVERIFY( info.isFile() );
+ QVERIFY( info.size() >= ((qint64)1 << maxSizeBits) + blockSize );
+}
+
+void tst_LargeFile::filePositioning()
+{
+ QFETCH( qint64, position );
+
+ QFile file("qt_largefile.tmp");
+ QVERIFY( file.open(QIODevice::ReadOnly) );
+
+ QVERIFY( file.seek(position) );
+ QCOMPARE( file.pos(), position );
+}
+
+void tst_LargeFile::fdPositioning()
+{
+ QFETCH( qint64, position );
+
+ fd_ = QT_OPEN("qt_largefile.tmp",
+ QT_OPEN_RDONLY | QT_OPEN_LARGEFILE);
+ QVERIFY( -1 != fd_ );
+
+ QFile file;
+ QVERIFY( file.open(fd_, QIODevice::ReadOnly) );
+ QCOMPARE( file.pos(), (qint64)0 );
+ QVERIFY( file.seek(position) );
+ QCOMPARE( file.pos(), position );
+
+ file.close();
+
+ QCOMPARE( QT_LSEEK(fd_, QT_OFF_T(0), SEEK_SET), QT_OFF_T(0) );
+ QCOMPARE( QT_LSEEK(fd_, QT_OFF_T(position), SEEK_SET), QT_OFF_T(position) );
+
+ QVERIFY( file.open(fd_, QIODevice::ReadOnly) );
+ QCOMPARE( QT_LSEEK(fd_, QT_OFF_T(0), SEEK_CUR), QT_OFF_T(position) );
+ QCOMPARE( file.pos(), position );
+ QVERIFY( file.seek(0) );
+ QCOMPARE( file.pos(), (qint64)0 );
+
+ file.close();
+
+ QVERIFY( !QT_CLOSE(fd_) );
+ fd_ = -1;
+}
+
+void tst_LargeFile::streamPositioning()
+{
+ QFETCH( qint64, position );
+
+#if defined(QT_LARGEFILE_SUPPORT) && defined(Q_CC_MSVC) && _MSC_VER < 1400
+ if (position >= (qint64)1 << 31)
+ QSKIP("MSVC 2003 doesn't have 64 bit versions of fseek/ftell.", SkipSingle);
+#endif
+
+ stream_ = QT_FOPEN("qt_largefile.tmp", "rb");
+ QVERIFY( 0 != stream_ );
+
+ QFile file;
+ QVERIFY( file.open(stream_, QIODevice::ReadOnly) );
+ QCOMPARE( file.pos(), (qint64)0 );
+ QVERIFY( file.seek(position) );
+ QCOMPARE( file.pos(), position );
+
+ file.close();
+
+ QVERIFY( !QT_FSEEK(stream_, QT_OFF_T(0), SEEK_SET) );
+ QCOMPARE( QT_FTELL(stream_), QT_OFF_T(0) );
+ QVERIFY( !QT_FSEEK(stream_, QT_OFF_T(position), SEEK_SET) );
+ QCOMPARE( QT_FTELL(stream_), QT_OFF_T(position) );
+
+ QVERIFY( file.open(stream_, QIODevice::ReadOnly) );
+ QCOMPARE( QT_FTELL(stream_), QT_OFF_T(position) );
+ QCOMPARE( file.pos(), position );
+ QVERIFY( file.seek(0) );
+ QCOMPARE( file.pos(), (qint64)0 );
+
+ file.close();
+
+ QVERIFY( !::fclose(stream_) );
+ stream_ = 0;
+}
+
+void tst_LargeFile::openFileForReading()
+{
+ largeFile.setFileName("qt_largefile.tmp");
+ QVERIFY( largeFile.open(QIODevice::ReadOnly) );
+}
+
+void tst_LargeFile::readFile()
+{
+ QFETCH( qint64, position );
+ QFETCH( QByteArray, block );
+ QCOMPARE( block.size(), blockSize );
+
+ QVERIFY( largeFile.size() >= position + blockSize );
+
+ QVERIFY( largeFile.seek(position) );
+ QCOMPARE( largeFile.pos(), position );
+
+ QCOMPARE( largeFile.read(blockSize), block );
+ QCOMPARE( largeFile.pos(), position + blockSize );
+}
+
+void tst_LargeFile::mapFile()
+{
+ QFETCH( qint64, position );
+ QFETCH( QByteArray, block );
+ QCOMPARE( block.size(), blockSize );
+
+ // Keep full block mapped to facilitate OS and/or internal reuse by Qt.
+ uchar *baseAddress = largeFile.map(position, blockSize);
+ QVERIFY( baseAddress );
+ QVERIFY( qEqual(block.begin(), block.end(), reinterpret_cast<char*>(baseAddress)) );
+
+ for (int offset = 1; offset < blockSize; ++offset) {
+ uchar *address = largeFile.map(position + offset, blockSize - offset);
+
+ QVERIFY( address );
+ if ( !qEqual(block.begin() + offset, block.end(), reinterpret_cast<char*>(address)) ) {
+ qDebug() << "Expected:" << block.toHex();
+ qDebug() << "Actual :" << QByteArray(reinterpret_cast<char*>(address), blockSize).toHex();
+ QVERIFY(false);
+ }
+
+ QVERIFY( largeFile.unmap( address ) );
+ }
+
+ QVERIFY( largeFile.unmap( baseAddress ) );
+}
+
+void tst_LargeFile::mapOffsetOverflow()
+{
+#if defined(Q_OS_MAC)
+ QSKIP("mmap'ping beyond EOF may succeed; generate bus error on access", SkipAll);
+#endif
+
+ // Out-of-range mappings should fail, and not silently clip the offset
+ for (int i = 50; i < 63; ++i) {
+ uchar *address = 0;
+
+ address = largeFile.map(((qint64)1 << i), blockSize);
+ QVERIFY( !address );
+
+ address = largeFile.map(((qint64)1 << i) + blockSize, blockSize);
+ QVERIFY( !address );
+ }
+}
+
+QTEST_APPLESS_MAIN(tst_LargeFile)
+#include "tst_largefile.moc"
+
diff --git a/tests/auto/corelib/io/qfile/noendofline.txt b/tests/auto/corelib/io/qfile/noendofline.txt
new file mode 100644
index 0000000000..e120842ad9
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/noendofline.txt
@@ -0,0 +1,3 @@
+Do not touch the content of this file.
+It shows a text file
+with no end-of-line-character on the last line \ No newline at end of file
diff --git a/tests/auto/corelib/io/qfile/qfile.pro b/tests/auto/corelib/io/qfile/qfile.pro
new file mode 100644
index 0000000000..f41d32789a
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/qfile.pro
@@ -0,0 +1,10 @@
+TEMPLATE = subdirs
+wince*|symbian:{
+ SUBDIRS = test
+} else {
+ SUBDIRS = test stdinprocess
+}
+
+!symbian:SUBDIRS += largefile
+
+CONFIG += parallel_test
diff --git a/tests/auto/corelib/io/qfile/qfile.qrc b/tests/auto/corelib/io/qfile/qfile.qrc
new file mode 100644
index 0000000000..2c63d8afeb
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/qfile.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/tst_qfileinfo/">
+ <file>resources/</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/corelib/io/qfile/rename-fallback.qrc b/tests/auto/corelib/io/qfile/rename-fallback.qrc
new file mode 100644
index 0000000000..c8a894a61d
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/rename-fallback.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>rename-fallback.qrc</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/corelib/io/qfile/resources/file1.ext1 b/tests/auto/corelib/io/qfile/resources/file1.ext1
new file mode 100644
index 0000000000..e56e15bb7d
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/resources/file1.ext1
@@ -0,0 +1 @@
+12345
diff --git a/tests/auto/corelib/io/qfile/stdinprocess/main.cpp b/tests/auto/corelib/io/qfile/stdinprocess/main.cpp
new file mode 100644
index 0000000000..57a8d904f5
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/stdinprocess/main.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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 <QtCore>
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ printf("usage: stdinprocess <all|line <0|1>>\n");
+ printf("echos all its input to its output.\n");
+ return 1;
+ }
+
+ QFile file;
+
+ if (strcmp(argv[1], "all") == 0) {
+ file.open(stdin, QFile::ReadWrite);
+ printf("%s", file.readAll().constData());
+ } else if (strcmp(argv[1], "line") == 0) {
+ if (strcmp(argv[2], "0") == 0) {
+ file.open(stdin, QFile::ReadWrite);
+ } else {
+ file.open(0, QFile::ReadWrite);
+ }
+
+ char line[1024];
+ while (file.readLine(line, sizeof(line)) > 0) {
+ printf("%s", line);
+ fflush(stdout);
+ }
+ }
+ return 0;
+}
diff --git a/tests/auto/corelib/io/qfile/stdinprocess/stdinprocess.pro b/tests/auto/corelib/io/qfile/stdinprocess/stdinprocess.pro
new file mode 100644
index 0000000000..bf791ffc61
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/stdinprocess/stdinprocess.pro
@@ -0,0 +1,6 @@
+SOURCES += main.cpp
+QT = core
+CONFIG -= app_bundle debug_and_release_target
+CONFIG += console
+
+
diff --git a/tests/auto/corelib/io/qfile/test/test.pro b/tests/auto/corelib/io/qfile/test/test.pro
new file mode 100644
index 0000000000..f4ec12f874
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/test/test.pro
@@ -0,0 +1,44 @@
+load(qttest_p4)
+SOURCES += ../tst_qfile.cpp
+
+wince*|symbian {
+ QT = core gui
+ files.files += ..\\dosfile.txt ..\\noendofline.txt ..\\testfile.txt \
+ ..\\testlog.txt ..\\two.dots.file ..\\tst_qfile.cpp \
+ ..\\Makefile ..\\forCopying.txt ..\\forRenaming.txt
+ files.path = .
+ resour.files += ..\\resources\\file1.ext1
+ resour.path = resources
+
+ DEPLOYMENT += files resour
+}
+
+wince* {
+ SOURCES += $$QT_SOURCE_TREE/src/corelib/kernel/qfunctions_wince.cpp # needed for QT_OPEN
+ DEFINES += SRCDIR=\\\"\\\"
+} else:symbian {
+ # do not define SRCDIR at all
+ TARGET.EPOCHEAPSIZE = 0x100000 0x3000000
+} else {
+ QT = core network
+ DEFINES += SRCDIR=\\\"$$PWD/../\\\"
+}
+
+RESOURCES += ../qfile.qrc ../rename-fallback.qrc ../copy-fallback.qrc
+
+TARGET = ../tst_qfile
+
+win32 {
+ CONFIG(debug, debug|release) {
+ TARGET = ../../debug/tst_qfile
+ } else {
+ TARGET = ../../release/tst_qfile
+ }
+ LIBS+=-lole32 -luuid
+}
+
+symbian {
+ LIBS+=-lefsrv
+}
+
+mac*:CONFIG+=insignificant_test
diff --git a/tests/auto/corelib/io/qfile/testfile.txt b/tests/auto/corelib/io/qfile/testfile.txt
new file mode 100644
index 0000000000..a5f25a118a
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/testfile.txt
@@ -0,0 +1,6 @@
+----------------------------------------------------------
+DO NOT CHANGE ANY CONTENT OR ACCESS RIGHTS OF THIS FILE!!!
+----------------------------------------------------------
+
+This demo file has only six lines
+and a size of exactly 245 Bytes.
diff --git a/tests/auto/corelib/io/qfile/testlog.txt b/tests/auto/corelib/io/qfile/testlog.txt
new file mode 100644
index 0000000000..bcc7222b2f
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/testlog.txt
@@ -0,0 +1,144 @@
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts
+2006-09-29 13:50:08.349: -- File log starts_
+2006-09-29 13:50:08.349: -- File log starts
diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp
new file mode 100644
index 0000000000..f2031497ed
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp
@@ -0,0 +1,3406 @@
+/****************************************************************************
+**
+** 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 <qplatformdefs.h>
+
+#include <QAbstractFileEngine>
+#include <QFSFileEngine>
+#include <QCoreApplication>
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
+#include <QHostInfo>
+#endif
+#include <QProcess>
+#ifndef Q_OS_WIN
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+#ifdef Q_OS_MAC
+# include <sys/mount.h>
+#elif defined(Q_OS_LINUX)
+# include <sys/vfs.h>
+#elif defined(Q_OS_FREEBSD)
+# include <sys/param.h>
+# include <sys/mount.h>
+#elif defined(Q_OS_IRIX)
+# include <sys/statfs.h>
+#elif defined(Q_OS_WINCE)
+# include <qplatformdefs.h>
+# include <private/qfsfileengine_p.h>
+#elif defined(Q_OS_SYMBIAN)
+# include <f32file.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include "../../../network-settings.h"
+
+#if defined(Q_OS_SYMBIAN)
+# define SRCDIR ""
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+#ifndef QT_OPEN_BINARY
+#define QT_OPEN_BINARY 0
+#endif
+
+Q_DECLARE_METATYPE(QFile::FileError)
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QFile : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QFile();
+ virtual ~tst_QFile();
+
+
+public slots:
+ void init();
+ void cleanup();
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void exists();
+ void open_data();
+ void open();
+ void openUnbuffered();
+ void size_data();
+ void size();
+ void sizeNoExist();
+ void seek();
+ void setSize();
+ void setSizeSeek();
+ void atEnd();
+ void readLine();
+ void readLine2();
+ void readLineNullInLine();
+ void readAll_data();
+ void readAll();
+ void readAllBuffer();
+ void readAllStdin();
+ void readLineStdin();
+ void readLineStdin_lineByLine();
+ void text();
+ void missingEndOfLine();
+ void readBlock();
+ void getch();
+ void ungetChar();
+ void createFile();
+ void append();
+ void permissions_data();
+ void permissions();
+ void setPermissions();
+ void copy();
+ void copyAfterFail();
+ void copyRemovesTemporaryFile() const;
+ void copyShouldntOverwrite();
+ void copyFallback();
+ void link();
+ void linkToDir();
+ void absolutePathLinkToRelativePath();
+ void readBrokenLink();
+ void readTextFile_data();
+ void readTextFile();
+ void readTextFile2();
+ void writeTextFile_data();
+ void writeTextFile();
+ /* void largeFileSupport(); */
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ void largeUncFileSupport();
+#endif
+ void tailFile();
+ void flush();
+ void bufferedRead();
+ void isSequential();
+ void encodeName();
+ void truncate();
+ void seekToPos();
+ void seekAfterEndOfFile();
+ void FILEReadWrite();
+ void i18nFileName_data();
+ void i18nFileName();
+ void longFileName_data();
+ void longFileName();
+ void fileEngineHandler();
+ void useQFileInAFileHandler();
+ void getCharFF();
+ void remove_and_exists();
+ void removeOpenFile();
+ void fullDisk();
+ void writeLargeDataBlock_data();
+ void writeLargeDataBlock();
+ void readFromWriteOnlyFile();
+ void writeToReadOnlyFile();
+ void virtualFile();
+ void textFile();
+ void rename_data();
+ void rename();
+ void renameWithAtEndSpecialFile() const;
+ void renameFallback();
+ void renameMultiple();
+ void appendAndRead();
+ void miscWithUncPathAsCurrentDir();
+ void standarderror();
+ void handle();
+ void nativeHandleLeaks();
+
+ void readEof_data();
+ void readEof();
+
+ void map_data();
+ void map();
+ void mapResource_data();
+ void mapResource();
+ void mapOpenMode_data();
+ void mapOpenMode();
+
+ void openStandardStreams();
+
+ void resize_data();
+ void resize();
+
+ void objectConstructors();
+#ifdef Q_OS_SYMBIAN
+ void platformSecurity_data();
+ void platformSecurity();
+#endif
+ void caseSensitivity();
+
+ void autocloseHandle();
+
+ // --- Task related tests below this line
+ void task167217();
+
+ void openDirectory();
+ void writeNothing();
+
+public:
+// disabled this test for the moment... it hangs
+ void invalidFile_data();
+ void invalidFile();
+
+private:
+ enum FileType {
+ OpenQFile,
+ OpenFd,
+ OpenStream,
+#ifdef Q_OS_SYMBIAN
+ OpenRFile,
+#endif
+ NumberOfFileTypes
+ };
+
+ void openStandardStreamsFileDescriptors();
+ void openStandardStreamsBufferedStreams();
+
+ bool openFd(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags)
+ {
+ int fdMode = QT_OPEN_LARGEFILE | QT_OPEN_BINARY;
+
+ // File will be truncated if in Write mode.
+ if (mode & QIODevice::WriteOnly)
+ fdMode |= QT_OPEN_WRONLY | QT_OPEN_TRUNC;
+ if (mode & QIODevice::ReadOnly)
+ fdMode |= QT_OPEN_RDONLY;
+
+ fd_ = QT_OPEN(qPrintable(file.fileName()), fdMode);
+
+ return (-1 != fd_) && file.open(fd_, mode, handleFlags);
+ }
+
+ bool openStream(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags)
+ {
+ char const *streamMode = "";
+
+ // File will be truncated if in Write mode.
+ if (mode & QIODevice::WriteOnly)
+ streamMode = "wb+";
+ else if (mode & QIODevice::ReadOnly)
+ streamMode = "rb";
+
+ stream_ = QT_FOPEN(qPrintable(file.fileName()), streamMode);
+
+ return stream_ && file.open(stream_, mode, handleFlags);
+ }
+
+#ifdef Q_OS_SYMBIAN
+ bool openRFile(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags)
+ {
+ //connect file server first time
+ if (!rfs_.Handle() && rfs_.Connect() != KErrNone)
+ return false;
+ //symbian does not like ./ in filenames, so open by absolute path
+ QString fileName(QDir::toNativeSeparators(QFileInfo(file).absoluteFilePath()));
+ TPtrC fn(fileName.utf16(), fileName.length());
+ TInt smode = 0;
+ if (mode & QIODevice::WriteOnly)
+ smode |= EFileWrite;
+ if (mode & QIODevice::ReadOnly)
+ smode |= EFileRead;
+ TInt r;
+ if ((mode & QIODevice::Truncate) || (!(mode & QIODevice::ReadOnly) && !(mode & QIODevice::Append))) {
+ r = rfile_.Replace(rfs_, fn, smode);
+ } else {
+ r = rfile_.Open(rfs_, fn, smode);
+ if (r == KErrNotFound && (mode & QIODevice::WriteOnly)) {
+ r = rfile_.Create(rfs_, fn, smode);
+ }
+ }
+ return (r == KErrNone) && file.open(rfile_, mode, handleFlags);
+ }
+#endif
+
+ bool openFile(QFile &file, QIODevice::OpenMode mode, FileType type = OpenQFile, QFile::FileHandleFlags handleFlags = QFile::DontCloseHandle)
+ {
+ if (mode & QIODevice::WriteOnly && !file.exists())
+ {
+ // Make sure the file exists
+ QFile createFile(file.fileName());
+ if (!createFile.open(QIODevice::ReadWrite))
+ return false;
+ }
+
+ // Note: openFd and openStream will truncate the file if write mode.
+ switch (type)
+ {
+ case OpenQFile:
+ return file.open(mode);
+
+ case OpenFd:
+ return openFd(file, mode, handleFlags);
+
+ case OpenStream:
+ return openStream(file, mode, handleFlags);
+#ifdef Q_OS_SYMBIAN
+ case OpenRFile:
+ return openRFile(file, mode, handleFlags);
+#endif
+ case NumberOfFileTypes:
+ break;
+ }
+
+ return false;
+ }
+
+ void closeFile(QFile &file)
+ {
+ file.close();
+
+ if (-1 != fd_)
+ QT_CLOSE(fd_);
+ if (stream_)
+ ::fclose(stream_);
+#ifdef Q_OS_SYMBIAN
+ if (rfile_.SubSessionHandle())
+ rfile_.Close();
+#endif
+
+ fd_ = -1;
+ stream_ = 0;
+ }
+
+ int fd_;
+ FILE *stream_;
+#ifdef Q_OS_SYMBIAN
+ RFs rfs_;
+ RFile rfile_;
+#endif
+};
+
+tst_QFile::tst_QFile()
+{
+}
+
+tst_QFile::~tst_QFile()
+{
+
+}
+
+void tst_QFile::init()
+{
+// TODO: Add initialization code here.
+// This will be executed immediately before each test is run.
+ fd_ = -1;
+ stream_ = 0;
+}
+
+void tst_QFile::cleanup()
+{
+// TODO: Add cleanup code here.
+// This will be executed immediately after each test is run.
+
+ // for copyFallback()
+ if (QFile::exists("file-copy-destination.txt")) {
+ QFile::setPermissions("file-copy-destination.txt",
+ QFile::ReadOwner | QFile::WriteOwner);
+ QFile::remove("file-copy-destination.txt");
+ }
+
+ // for renameFallback()
+ QFile::remove("file-rename-destination.txt");
+
+ // for copyAfterFail()
+ QFile::remove("file-to-be-copied.txt");
+ QFile::remove("existing-file.txt");
+ QFile::remove("copied-file-1.txt");
+ QFile::remove("copied-file-2.txt");
+
+ // for renameMultiple()
+ QFile::remove("file-to-be-renamed.txt");
+ QFile::remove("existing-file.txt");
+ QFile::remove("file-renamed-once.txt");
+ QFile::remove("file-renamed-twice.txt");
+
+ if (-1 != fd_)
+ QT_CLOSE(fd_);
+ if (stream_)
+ ::fclose(stream_);
+}
+
+void tst_QFile::initTestCase()
+{
+ QFile::remove("noreadfile");
+
+ // create a file and make it read-only
+ QFile file("readonlyfile");
+ file.open(QFile::WriteOnly);
+ file.write("a", 1);
+ file.close();
+ file.setPermissions(QFile::ReadOwner);
+
+ // create another file and make it not readable
+ file.setFileName("noreadfile");
+ file.open(QFile::WriteOnly);
+ file.write("b", 1);
+ file.close();
+ file.setPermissions(0);
+}
+
+void tst_QFile::cleanupTestCase()
+{
+ // clean up the files we created
+ QFile::remove("readonlyfile");
+ QFile::remove("noreadfile");
+ QFile::remove("myLink.lnk");
+ QFile::remove("appendme.txt");
+ QFile::remove("createme.txt");
+ QFile::remove("file.txt");
+ QFile::remove("genfile.txt");
+ QFile::remove("seekToPos.txt");
+ QFile::remove("setsizeseek.txt");
+ QFile::remove("stdfile.txt");
+ QFile::remove("textfile.txt");
+ QFile::remove("truncate.txt");
+ QFile::remove("winfile.txt");
+ QFile::remove("writeonlyfile");
+ QFile::remove("largeblockfile.txt");
+ QFile::remove("tst_qfile_copy.cpp");
+ QFile::remove("nullinline.txt");
+ QFile::remove("myLink2.lnk");
+ QFile::remove("resources");
+ QFile::remove("qfile_map_testfile");
+ QFile::remove("readAllBuffer.txt");
+ QFile::remove("qt_file.tmp");
+ QFile::remove("File.txt");
+}
+
+//------------------------------------------
+// The 'testfile' is currently just a
+// testfile. The path of this file, the
+// attributes and the contents itself
+// will be changed as far as we have a
+// proper way to handle files in the
+// testing environment.
+//------------------------------------------
+
+void tst_QFile::exists()
+{
+ QFile f( SRCDIR "testfile.txt" );
+ QCOMPARE( f.exists(), (bool)TRUE );
+
+ QFile file("nobodyhassuchafile");
+ file.remove();
+ QVERIFY(!file.exists());
+
+ QFile file2("nobodyhassuchafile");
+ QVERIFY(file2.open(QIODevice::WriteOnly));
+ file2.close();
+
+ QVERIFY(file.exists());
+
+ QVERIFY(file.open(QIODevice::WriteOnly));
+ file.close();
+ QVERIFY(file.exists());
+
+ file.remove();
+ QVERIFY(!file.exists());
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ QFile unc("//" + QtNetworkSettings::winServerName() + "/testshare/readme.txt");
+ QVERIFY(unc.exists());
+#endif
+}
+
+void tst_QFile::open_data()
+{
+ QTest::addColumn<QString>("filename");
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<bool>("ok");
+ QTest::addColumn<QFile::FileError>("status");
+
+#ifdef Q_OS_MAC
+ static const QString denied("Operation not permitted");
+#else
+ static const QString denied("Permission denied");
+#endif
+ QTest::newRow( "exist_readOnly" )
+ << QString(SRCDIR "testfile.txt") << int(QIODevice::ReadOnly)
+ << (bool)TRUE << QFile::NoError;
+
+ QTest::newRow( "exist_writeOnly" )
+ << QString("readonlyfile")
+ << int(QIODevice::WriteOnly)
+ << (bool)FALSE
+ << QFile::OpenError;
+
+ QTest::newRow( "exist_append" )
+ << QString("readonlyfile") << int(QIODevice::Append)
+ << (bool)FALSE << QFile::OpenError;
+
+ QTest::newRow( "nonexist_readOnly" )
+ << QString("nonExist.txt") << int(QIODevice::ReadOnly)
+ << (bool)FALSE << QFile::OpenError;
+
+ QTest::newRow("emptyfile")
+ << QString("")
+ << int(QIODevice::ReadOnly)
+ << (bool)FALSE
+ << QFile::OpenError;
+
+ QTest::newRow("nullfile") << QString() << int(QIODevice::ReadOnly) << (bool)FALSE
+ << QFile::OpenError;
+
+ QTest::newRow("two-dots") << QString(SRCDIR "two.dots.file") << int(QIODevice::ReadOnly) << (bool)TRUE
+ << QFile::NoError;
+
+ QTest::newRow("readonlyfile") << QString("readonlyfile") << int(QIODevice::WriteOnly)
+ << (bool)FALSE << QFile::OpenError;
+ QTest::newRow("noreadfile") << QString("noreadfile") << int(QIODevice::ReadOnly)
+ << (bool)FALSE << QFile::OpenError;
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ QTest::newRow("//./PhysicalDrive0") << QString("//./PhysicalDrive0") << int(QIODevice::ReadOnly)
+ << (bool)TRUE << QFile::NoError;
+ QTest::newRow("uncFile") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri" << int(QIODevice::ReadOnly)
+ << true << QFile::NoError;
+#endif
+}
+
+void tst_QFile::open()
+{
+ QFETCH( QString, filename );
+ QFETCH( int, mode );
+
+ QFile f( filename );
+
+ QFETCH( bool, ok );
+
+#if defined(Q_OS_SYMBIAN)
+ if (qstrcmp(QTest::currentDataTag(), "noreadfile") == 0)
+ QSKIP("Symbian does not support non-readable files", SkipSingle);
+#elif defined(Q_OS_UNIX)
+ if (::getuid() == 0)
+ // root and Chuck Norris don't care for file permissions. Skip.
+ QSKIP("Running this test as root doesn't make sense", SkipAll);
+#endif
+
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ QEXPECT_FAIL("noreadfile", "Windows does not currently support non-readable files.", Abort);
+#endif
+ if (filename.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::open: No file name specified");
+
+ QCOMPARE(f.open( QIODevice::OpenMode(mode) ), ok);
+
+ QTEST( f.error(), "status" );
+}
+
+void tst_QFile::openUnbuffered()
+{
+ QFile file(SRCDIR "testfile.txt");
+ QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered));
+ char c = '\0';
+ QVERIFY(file.seek(1));
+ QCOMPARE(file.pos(), qint64(1));
+ QVERIFY(file.getChar(&c));
+ QCOMPARE(file.pos(), qint64(2));
+ char d = '\0';
+ QVERIFY(file.seek(3));
+ QCOMPARE(file.pos(), qint64(3));
+ QVERIFY(file.getChar(&d));
+ QCOMPARE(file.pos(), qint64(4));
+ QVERIFY(file.seek(1));
+ QCOMPARE(file.pos(), qint64(1));
+ char c2 = '\0';
+ QVERIFY(file.getChar(&c2));
+ QCOMPARE(file.pos(), qint64(2));
+ QVERIFY(file.seek(3));
+ QCOMPARE(file.pos(), qint64(3));
+ char d2 = '\0';
+ QVERIFY(file.getChar(&d2));
+ QCOMPARE(file.pos(), qint64(4));
+ QCOMPARE(c, c2);
+ QCOMPARE(d, d2);
+ QCOMPARE(c, '-');
+ QCOMPARE(d, '-');
+}
+
+void tst_QFile::size_data()
+{
+ QTest::addColumn<QString>("filename");
+ QTest::addColumn<qint64>("size");
+
+ QTest::newRow( "exist01" ) << QString(SRCDIR "testfile.txt") << (qint64)245;
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ // Only test UNC on Windows./
+ QTest::newRow("unc") << "//" + QString(QtNetworkSettings::winServerName() + "/testshare/test.pri") << (qint64)34;
+#endif
+}
+
+void tst_QFile::size()
+{
+ QFETCH( QString, filename );
+ QFETCH( qint64, size );
+
+#ifdef Q_WS_WINCE
+ filename = QFileInfo(filename).absoluteFilePath();
+#endif
+
+ {
+ QFile f( filename );
+ QCOMPARE( f.size(), size );
+
+ QVERIFY( f.open(QIODevice::ReadOnly) );
+ QCOMPARE( f.size(), size );
+ }
+
+ {
+ QFile f;
+ FILE* stream = QT_FOPEN(filename.toLocal8Bit().constData(), "rb");
+ QVERIFY( stream );
+ QVERIFY( f.open(stream, QIODevice::ReadOnly) );
+ QCOMPARE( f.size(), size );
+
+ f.close();
+ fclose(stream);
+ }
+
+ {
+#ifdef Q_WS_WINCE
+ QSKIP("Currently low level file I/O not well supported on Windows CE", SkipSingle);
+#endif
+ QFile f;
+
+ int fd = QT_OPEN(filename.toLocal8Bit().constData(), QT_OPEN_RDONLY);
+
+ QVERIFY( fd != -1 );
+ QVERIFY( f.open(fd, QIODevice::ReadOnly) );
+ QCOMPARE( f.size(), size );
+
+ f.close();
+ QT_CLOSE(fd);
+ }
+}
+
+void tst_QFile::sizeNoExist()
+{
+ QFile file("nonexist01");
+ QVERIFY( !file.exists() );
+ QCOMPARE( file.size(), (qint64)0 );
+ QVERIFY( !file.open(QIODevice::ReadOnly) );
+}
+
+void tst_QFile::seek()
+{
+ QFile::remove("newfile.txt");
+ QFile file("newfile.txt");
+ file.open(QIODevice::WriteOnly);
+ QCOMPARE(file.size(), qint64(0));
+ QCOMPARE(file.pos(), qint64(0));
+ QVERIFY(file.seek(10));
+ QCOMPARE(file.pos(), qint64(10));
+ QCOMPARE(file.size(), qint64(0));
+ file.close();
+ QFile::remove("newfile.txt");
+}
+
+void tst_QFile::setSize()
+{
+ DEPENDS_ON( "size" );
+
+ if ( QFile::exists( "createme.txt" ) )
+ QFile::remove( "createme.txt" );
+ QVERIFY( !QFile::exists( "createme.txt" ) );
+
+ QFile f("createme.txt");
+ QVERIFY(f.open(QIODevice::Truncate | QIODevice::ReadWrite));
+ f.putChar('a');
+
+ f.seek(0);
+ char c = '\0';
+ f.getChar(&c);
+ QCOMPARE(c, 'a');
+
+ QCOMPARE(f.size(), (qlonglong)1);
+ bool ok = f.resize(99);
+ QVERIFY(ok);
+ QCOMPARE(f.size(), (qlonglong)99);
+
+ f.seek(0);
+ c = '\0';
+ f.getChar(&c);
+ QCOMPARE(c, 'a');
+
+ QVERIFY(f.resize(1));
+ QCOMPARE(f.size(), (qlonglong)1);
+
+ f.seek(0);
+ c = '\0';
+ f.getChar(&c);
+ QCOMPARE(c, 'a');
+
+ f.close();
+
+ QCOMPARE(f.size(), (qlonglong)1);
+ QVERIFY(f.resize(100));
+ QCOMPARE(f.size(), (qlonglong)100);
+ QVERIFY(f.resize(50));
+ QCOMPARE(f.size(), (qlonglong)50);
+}
+
+void tst_QFile::setSizeSeek()
+{
+ QFile::remove("setsizeseek.txt");
+ QFile f("setsizeseek.txt");
+ QVERIFY(f.open(QFile::WriteOnly));
+ f.write("ABCD");
+
+ QCOMPARE(f.pos(), qint64(4));
+ f.resize(2);
+ QCOMPARE(f.pos(), qint64(2));
+ f.resize(4);
+ QCOMPARE(f.pos(), qint64(2));
+ f.resize(0);
+ QCOMPARE(f.pos(), qint64(0));
+ f.resize(4);
+ QCOMPARE(f.pos(), qint64(0));
+
+ f.seek(3);
+ QCOMPARE(f.pos(), qint64(3));
+ f.resize(2);
+ QCOMPARE(f.pos(), qint64(2));
+}
+
+void tst_QFile::atEnd()
+{
+ QFile f( SRCDIR "testfile.txt" );
+ QVERIFY(f.open( QIODevice::ReadOnly ));
+
+ int size = f.size();
+ f.seek( size );
+
+ bool end = f.atEnd();
+ f.close();
+ QCOMPARE( end, (bool)TRUE );
+}
+
+void tst_QFile::readLine()
+{
+ QFile f( SRCDIR "testfile.txt" );
+ QVERIFY(f.open( QIODevice::ReadOnly ));
+
+ int i = 0;
+ char p[128];
+ int foo;
+ while ( (foo=f.readLine( p, 128 )) > 0 ) {
+ ++i;
+ if ( i == 5 ) {
+ QCOMPARE( p[0], 'T' );
+ QCOMPARE( p[3], 's' );
+ QCOMPARE( p[11], 'i' );
+ }
+ }
+ f.close();
+ QCOMPARE( i, 6 );
+}
+
+void tst_QFile::readLine2()
+{
+ QFile f( SRCDIR "testfile.txt" );
+ f.open( QIODevice::ReadOnly );
+
+ char p[128];
+ QCOMPARE(f.readLine(p, 60), qlonglong(59));
+ QCOMPARE(f.readLine(p, 60), qlonglong(59));
+ memset(p, '@', sizeof(p));
+ QCOMPARE(f.readLine(p, 60), qlonglong(59));
+
+ QCOMPARE(p[57], '-');
+ QCOMPARE(p[58], '\n');
+ QCOMPARE(p[59], '\0');
+ QCOMPARE(p[60], '@');
+}
+
+void tst_QFile::readLineNullInLine()
+{
+ QFile::remove("nullinline.txt");
+ QFile file("nullinline.txt");
+ QVERIFY(file.open(QIODevice::ReadWrite));
+ QVERIFY(file.write("linewith\0null\nanotherline\0withnull\n\0\nnull\0", 42) > 0);
+ QVERIFY(file.flush());
+ file.reset();
+
+ QCOMPARE(file.readLine(), QByteArray("linewith\0null\n", 14));
+ QCOMPARE(file.readLine(), QByteArray("anotherline\0withnull\n", 21));
+ QCOMPARE(file.readLine(), QByteArray("\0\n", 2));
+ QCOMPARE(file.readLine(), QByteArray("null\0", 5));
+ QCOMPARE(file.readLine(), QByteArray());
+}
+
+void tst_QFile::readAll_data()
+{
+ QTest::addColumn<bool>("textMode");
+ QTest::addColumn<QString>("fileName");
+ QTest::newRow( "TextMode unixfile" ) << true << SRCDIR "testfile.txt";
+ QTest::newRow( "BinaryMode unixfile" ) << false << SRCDIR "testfile.txt";
+ QTest::newRow( "TextMode dosfile" ) << true << SRCDIR "dosfile.txt";
+ QTest::newRow( "BinaryMode dosfile" ) << false << SRCDIR "dosfile.txt";
+ QTest::newRow( "TextMode bigfile" ) << true << SRCDIR "tst_qfile.cpp";
+ QTest::newRow( "BinaryMode bigfile" ) << false << SRCDIR "tst_qfile.cpp";
+ QVERIFY(QFile(SRCDIR "tst_qfile.cpp").size() > 64*1024);
+}
+
+void tst_QFile::readAll()
+{
+ QFETCH( bool, textMode );
+ QFETCH( QString, fileName );
+
+ QFile file(fileName);
+ if (textMode)
+ QVERIFY(file.open(QFile::Text | QFile::ReadOnly));
+ else
+ QVERIFY(file.open(QFile::ReadOnly));
+
+ QByteArray a = file.readAll();
+ file.reset();
+ QVERIFY(file.pos() == 0);
+
+ QVERIFY(file.bytesAvailable() > 7);
+ QByteArray b = file.read(1);
+ char x;
+ file.getChar(&x);
+ b.append(x);
+ b.append(file.read(5));
+ b.append(file.readAll());
+
+ QCOMPARE(a, b);
+}
+
+void tst_QFile::readAllBuffer()
+{
+ QString fileName = QLatin1String("readAllBuffer.txt");
+
+ QFile::remove(fileName);
+
+ QFile writer(fileName);
+ QFile reader(fileName);
+
+ QByteArray data1("This is arguably a very simple text.");
+ QByteArray data2("This is surely not as simple a test.");
+
+ QVERIFY( writer.open(QIODevice::ReadWrite | QIODevice::Unbuffered) );
+ QVERIFY( reader.open(QIODevice::ReadOnly) );
+
+ QCOMPARE( writer.write(data1), qint64(data1.size()) );
+ QVERIFY( writer.seek(0) );
+
+ QByteArray result;
+ result = reader.read(18);
+ QCOMPARE( result.size(), 18 );
+
+ QCOMPARE( writer.write(data2), qint64(data2.size()) ); // new data, old version buffered in reader
+ QCOMPARE( writer.write(data2), qint64(data2.size()) ); // new data, unbuffered in reader
+
+ result += reader.readAll();
+
+ QCOMPARE( result, data1 + data2 );
+
+ QFile::remove(fileName);
+}
+
+void tst_QFile::readAllStdin()
+{
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QSKIP("Currently no stdin/out supported for Windows CE or Symbian", SkipAll);
+#endif
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QByteArray lotsOfData(1024, '@'); // 10 megs
+
+ QProcess process;
+ process.start("stdinprocess/stdinprocess all");
+ QVERIFY( process.waitForStarted() );
+ for (int i = 0; i < 5; ++i) {
+ QTest::qWait(1000);
+ process.write(lotsOfData);
+ while (process.bytesToWrite() > 0) {
+ QVERIFY(process.waitForBytesWritten());
+ }
+ }
+
+ process.closeWriteChannel();
+ process.waitForFinished();
+ QCOMPARE(process.readAll().size(), lotsOfData.size() * 5);
+#endif
+}
+
+void tst_QFile::readLineStdin()
+{
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QSKIP("Currently no stdin/out supported for Windows CE or Symbian", SkipAll);
+#endif
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+
+ QByteArray lotsOfData(1024, '@'); // 10 megs
+ for (int i = 0; i < lotsOfData.size(); ++i) {
+ if ((i % 32) == 31)
+ lotsOfData[i] = '\n';
+ else
+ lotsOfData[i] = char('0' + i % 32);
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ QProcess process;
+ process.start(QString("stdinprocess/stdinprocess line %1").arg(i), QIODevice::Text | QIODevice::ReadWrite);
+ for (int i = 0; i < 5; ++i) {
+ QTest::qWait(1000);
+ process.write(lotsOfData);
+ while (process.bytesToWrite() > 0) {
+ QVERIFY(process.waitForBytesWritten());
+ }
+ }
+
+ process.closeWriteChannel();
+ QVERIFY(process.waitForFinished(5000));
+
+ QByteArray array = process.readAll();
+ QCOMPARE(array.size(), lotsOfData.size() * 5);
+ for (int i = 0; i < array.size(); ++i) {
+ if ((i % 32) == 31)
+ QCOMPARE(char(array[i]), '\n');
+ else
+ QCOMPARE(char(array[i]), char('0' + i % 32));
+ }
+ }
+#endif
+}
+
+void tst_QFile::readLineStdin_lineByLine()
+{
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QSKIP("Currently no stdin/out supported for Windows CE", SkipAll);
+#endif
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ for (int i = 0; i < 2; ++i) {
+ QProcess process;
+ process.start(QString("stdinprocess/stdinprocess line %1").arg(i), QIODevice::Text | QIODevice::ReadWrite);
+ QVERIFY(process.waitForStarted());
+
+ for (int j = 0; j < 3; ++j) {
+ QByteArray line = "line " + QByteArray::number(j) + "\n";
+ QCOMPARE(process.write(line), qint64(line.size()));
+ QVERIFY(process.waitForBytesWritten(2000));
+ if (process.bytesAvailable() == 0)
+ QVERIFY(process.waitForReadyRead(2000));
+ QCOMPARE(process.readAll(), line);
+ }
+
+ process.closeWriteChannel();
+ QVERIFY(process.waitForFinished(5000));
+ }
+#endif
+}
+
+void tst_QFile::text()
+{
+ // dosfile.txt is a binary CRLF file
+ QFile file(SRCDIR "dosfile.txt");
+ QVERIFY(file.open(QFile::Text | QFile::ReadOnly));
+ QCOMPARE(file.readLine(),
+ QByteArray("/dev/system/root / reiserfs acl,user_xattr 1 1\n"));
+ QCOMPARE(file.readLine(),
+ QByteArray("/dev/sda1 /boot ext3 acl,user_xattr 1 2\n"));
+ file.ungetChar('\n');
+ file.ungetChar('2');
+ QCOMPARE(file.readLine().constData(), QByteArray("2\n").constData());
+}
+
+void tst_QFile::missingEndOfLine()
+{
+ QFile file(SRCDIR "noendofline.txt");
+ QVERIFY(file.open(QFile::ReadOnly));
+
+ int nlines = 0;
+ while (!file.atEnd()) {
+ ++nlines;
+ file.readLine();
+ }
+
+ QCOMPARE(nlines, 3);
+}
+
+void tst_QFile::readBlock()
+{
+ QFile f( SRCDIR "testfile.txt" );
+ f.open( QIODevice::ReadOnly );
+
+ int length = 0;
+ char p[256];
+ length = f.read( p, 256 );
+ f.close();
+ QCOMPARE( length, 245 );
+ QCOMPARE( p[59], 'D' );
+ QCOMPARE( p[178], 'T' );
+ QCOMPARE( p[199], 'l' );
+}
+
+void tst_QFile::getch()
+{
+ QFile f( SRCDIR "testfile.txt" );
+ f.open( QIODevice::ReadOnly );
+
+ char c;
+ int i = 0;
+ while (f.getChar(&c)) {
+ QCOMPARE(f.pos(), qint64(i + 1));
+ if ( i == 59 )
+ QCOMPARE( c, 'D' );
+ ++i;
+ }
+ f.close();
+ QCOMPARE( i, 245 );
+}
+
+void tst_QFile::ungetChar()
+{
+ QFile f(SRCDIR "testfile.txt");
+ QVERIFY(f.open(QIODevice::ReadOnly));
+
+ QByteArray array = f.readLine();
+ QCOMPARE(array.constData(), "----------------------------------------------------------\n");
+ f.ungetChar('\n');
+
+ array = f.readLine();
+ QCOMPARE(array.constData(), "\n");
+
+ f.ungetChar('\n');
+ f.ungetChar('-');
+ f.ungetChar('-');
+
+ array = f.readLine();
+ QCOMPARE(array.constData(), "--\n");
+
+ QFile::remove("genfile.txt");
+ QFile out("genfile.txt");
+ QVERIFY(out.open(QIODevice::ReadWrite));
+ out.write("123");
+ out.seek(0);
+ QCOMPARE(out.readAll().constData(), "123");
+ out.ungetChar('3');
+ out.write("4");
+ out.seek(0);
+ QCOMPARE(out.readAll().constData(), "124");
+ out.ungetChar('4');
+ out.ungetChar('2');
+ out.ungetChar('1');
+ char buf[3];
+ QCOMPARE(out.read(buf, sizeof(buf)), qint64(3));
+ QCOMPARE(buf[0], '1');
+ QCOMPARE(buf[1], '2');
+ QCOMPARE(buf[2], '4');
+}
+
+void tst_QFile::invalidFile_data()
+{
+ QTest::addColumn<QString>("fileName");
+#if !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN)
+ QTest::newRow( "x11" ) << QString( "qwe//" );
+#else
+ QTest::newRow( "colon1" ) << QString( "fail:invalid" );
+ QTest::newRow( "colon2" ) << QString( "f:ail:invalid" );
+ QTest::newRow( "colon3" ) << QString( ":failinvalid" );
+ QTest::newRow( "forwardslash" ) << QString( "fail/invalid" );
+ QTest::newRow( "asterisk" ) << QString( "fail*invalid" );
+ QTest::newRow( "questionmark" ) << QString( "fail?invalid" );
+ QTest::newRow( "quote" ) << QString( "fail\"invalid" );
+ QTest::newRow( "lt" ) << QString( "fail<invalid" );
+ QTest::newRow( "gt" ) << QString( "fail>invalid" );
+ QTest::newRow( "pipe" ) << QString( "fail|invalid" );
+#endif
+}
+
+void tst_QFile::invalidFile()
+{
+ QFETCH( QString, fileName );
+ QFile f( fileName );
+ QVERIFY( !f.open( QIODevice::ReadWrite ) );
+}
+
+void tst_QFile::createFile()
+{
+ if ( QFile::exists( "createme.txt" ) )
+ QFile::remove( "createme.txt" );
+ QVERIFY( !QFile::exists( "createme.txt" ) );
+
+ QFile f( "createme.txt" );
+ QVERIFY( f.open( QIODevice::WriteOnly ) );
+ f.close();
+ QVERIFY( QFile::exists( "createme.txt" ) );
+}
+
+void tst_QFile::append()
+{
+ const QString name("appendme.txt");
+ if (QFile::exists(name))
+ QFile::remove(name);
+ QVERIFY(!QFile::exists(name));
+
+ QFile f(name);
+ QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate));
+ f.putChar('a');
+ f.close();
+
+ QVERIFY(f.open(QIODevice::Append));
+ QVERIFY(f.pos() == 1);
+ f.putChar('a');
+ f.close();
+ QCOMPARE(int(f.size()), 2);
+}
+
+void tst_QFile::permissions_data()
+{
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<uint>("perms");
+ QTest::addColumn<bool>("expected");
+
+ QTest::newRow("data0") << QCoreApplication::instance()->applicationFilePath() << uint(QFile::ExeUser) << true;
+ QTest::newRow("data1") << SRCDIR "tst_qfile.cpp" << uint(QFile::ReadUser) << true;
+// QTest::newRow("data2") << "tst_qfile.cpp" << int(QFile::WriteUser) << false;
+ QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ReadUser) << true;
+ QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::WriteUser) << false;
+ QTest::newRow("resource3") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ExeUser) << false;
+}
+
+void tst_QFile::permissions()
+{
+#if defined(Q_OS_SYMBIAN)
+ if (qstrcmp(QTest::currentDataTag(), "data0") == 0)
+ QSKIP("Symbian does not have execution permissions", SkipSingle);
+#endif
+ QFETCH(QString, file);
+ QFETCH(uint, perms);
+ QFETCH(bool, expected);
+ QFile f(file);
+ QCOMPARE(((f.permissions() & perms) == QFile::Permissions(perms)), expected);
+ QCOMPARE(((QFile::permissions(file) & perms) == QFile::Permissions(perms)), expected);
+}
+
+void tst_QFile::setPermissions()
+{
+ DEPENDS_ON( "permissions" ); //if that doesn't work...
+
+ if ( QFile::exists( "createme.txt" ) )
+ QFile::remove( "createme.txt" );
+ QVERIFY( !QFile::exists( "createme.txt" ) );
+
+ QFile f("createme.txt");
+ QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate));
+ f.putChar('a');
+ f.close();
+
+ QFile::Permissions perms(QFile::WriteUser | QFile::ReadUser);
+ QVERIFY(f.setPermissions(perms));
+ QVERIFY((f.permissions() & perms) == perms);
+
+}
+
+void tst_QFile::copy()
+{
+ QFile::setPermissions("tst_qfile_copy.cpp", QFile::WriteUser);
+ QFile::remove("tst_qfile_copy.cpp");
+ QFile::remove("test2");
+ QVERIFY(QFile::copy(SRCDIR "tst_qfile.cpp", "tst_qfile_copy.cpp"));
+ QFile in1(SRCDIR "tst_qfile.cpp"), in2("tst_qfile_copy.cpp");
+ QVERIFY(in1.open(QFile::ReadOnly));
+ QVERIFY(in2.open(QFile::ReadOnly));
+ QByteArray data1 = in1.readAll(), data2 = in2.readAll();
+ QCOMPARE(data1, data2);
+ QFile::remove( "main_copy.cpp" );
+
+ QFile::copy(QDir::currentPath(), QDir::currentPath() + QLatin1String("/test2"));
+}
+
+void tst_QFile::copyAfterFail()
+{
+ QFile file1("file-to-be-copied.txt");
+ QFile file2("existing-file.txt");
+
+ QVERIFY(file1.open(QIODevice::ReadWrite) && "(test-precondition)");
+ QVERIFY(file2.open(QIODevice::ReadWrite) && "(test-precondition)");
+ file2.close();
+ QVERIFY(!QFile::exists("copied-file-1.txt") && "(test-precondition)");
+ QVERIFY(!QFile::exists("copied-file-2.txt") && "(test-precondition)");
+
+ QVERIFY(!file1.copy("existing-file.txt"));
+ QCOMPARE(file1.error(), QFile::CopyError);
+
+ QVERIFY(file1.copy("copied-file-1.txt"));
+ QVERIFY(!file1.isOpen());
+ QCOMPARE(file1.error(), QFile::NoError);
+
+ QVERIFY(!file1.copy("existing-file.txt"));
+ QCOMPARE(file1.error(), QFile::CopyError);
+
+ QVERIFY(file1.copy("copied-file-2.txt"));
+ QVERIFY(!file1.isOpen());
+ QCOMPARE(file1.error(), QFile::NoError);
+
+ QVERIFY(QFile::exists("copied-file-1.txt"));
+ QVERIFY(QFile::exists("copied-file-2.txt"));
+
+ QVERIFY(QFile::remove("file-to-be-copied.txt") && "(test-cleanup)");
+ QVERIFY(QFile::remove("existing-file.txt") && "(test-cleanup)");
+ QVERIFY(QFile::remove("copied-file-1.txt") && "(test-cleanup)");
+ QVERIFY(QFile::remove("copied-file-2.txt") && "(test-cleanup)");
+}
+
+void tst_QFile::copyRemovesTemporaryFile() const
+{
+ const QString newName(QLatin1String("copyRemovesTemporaryFile"));
+ QVERIFY(QFile::copy(SRCDIR "forCopying.txt", newName));
+
+ QVERIFY(!QFile::exists(QLatin1String( SRCDIR "qt_temp.XXXXXX")));
+ QVERIFY(QFile::remove(newName));
+}
+
+void tst_QFile::copyShouldntOverwrite()
+{
+ // Copy should not overwrite existing files.
+ QFile::remove("tst_qfile.cpy");
+ QFile file(SRCDIR "tst_qfile.cpp");
+ QVERIFY(file.copy("tst_qfile.cpy"));
+#if defined(Q_OS_SYMBIAN)
+ bool ok = QFile::setPermissions("tst_qfile.cpy", QFile::WriteUser);
+#else
+ bool ok = QFile::setPermissions("tst_qfile.cpy", QFile::WriteOther);
+#endif
+ QVERIFY(ok);
+ QVERIFY(!file.copy("tst_qfile.cpy"));
+ QFile::remove("tst_qfile.cpy");
+}
+
+void tst_QFile::copyFallback()
+{
+ // Using a resource file to trigger QFile::copy's fallback handling
+ QFile file(":/copy-fallback.qrc");
+ QFile::remove("file-copy-destination.txt");
+
+ QVERIFY2(file.exists(), "test precondition");
+ QVERIFY2(!QFile::exists("file-copy-destination.txt"), "test precondition");
+
+ // Fallback copy of closed file.
+ QVERIFY(file.copy("file-copy-destination.txt"));
+ QVERIFY(QFile::exists("file-copy-destination.txt"));
+ QVERIFY(!file.isOpen());
+
+#ifdef Q_WS_WINCE
+ // Need to reset permissions on Windows to be able to delete
+ QVERIFY(QFile::setPermissions("file-copy-destination.txt",
+ QFile::WriteOther));
+#else
+ // Need to reset permissions on Windows to be able to delete
+ QVERIFY(QFile::setPermissions("file-copy-destination.txt",
+ QFile::ReadOwner | QFile::WriteOwner));
+#endif
+ QVERIFY(QFile::remove("file-copy-destination.txt"));
+
+ // Fallback copy of open file.
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QVERIFY(file.copy("file-copy-destination.txt"));
+ QVERIFY(QFile::exists("file-copy-destination.txt"));
+ QVERIFY(!file.isOpen());
+
+ file.close();
+ QFile::remove("file-copy-destination.txt");
+}
+
+#ifdef Q_OS_WIN
+#include <objbase.h>
+#include <shlobj.h>
+#endif
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+static QString getWorkingDirectoryForLink(const QString &linkFileName)
+{
+ bool neededCoInit = false;
+ QString ret;
+
+ IShellLink *psl;
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
+ if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
+ neededCoInit = true;
+ CoInitialize(NULL);
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
+ }
+
+ if (SUCCEEDED(hres)) { // Get pointer to the IPersistFile interface.
+ IPersistFile *ppf;
+ hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
+ if (SUCCEEDED(hres)) {
+ hres = ppf->Load((LPOLESTR)linkFileName.utf16(), STGM_READ);
+ //The original path of the link is retrieved. If the file/folder
+ //was moved, the return value still have the old path.
+ if(SUCCEEDED(hres)) {
+ wchar_t szGotPath[MAX_PATH];
+ if (psl->GetWorkingDirectory(szGotPath, MAX_PATH) == NOERROR)
+ ret = QString::fromWCharArray(szGotPath);
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+
+ if (neededCoInit) {
+ CoUninitialize();
+ }
+
+ return ret;
+}
+#endif
+
+void tst_QFile::link()
+{
+#if defined(Q_OS_SYMBIAN)
+ QSKIP("Symbian does not support links", SkipAll);
+#endif
+ QFile::remove("myLink.lnk");
+
+ QFileInfo info1(SRCDIR "tst_qfile.cpp");
+ QString referenceTarget = QDir::cleanPath(info1.absoluteFilePath());
+
+ QVERIFY(QFile::link(SRCDIR "tst_qfile.cpp", "myLink.lnk"));
+
+ QFileInfo info2("myLink.lnk");
+ QVERIFY(info2.isSymLink());
+ QCOMPARE(info2.symLinkTarget(), referenceTarget);
+
+ QFile link("myLink.lnk");
+ QVERIFY(link.open(QIODevice::ReadOnly));
+ QCOMPARE(link.symLinkTarget(), referenceTarget);
+ link.close();
+
+ QCOMPARE(QFile::symLinkTarget("myLink.lnk"), referenceTarget);
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ QString wd = getWorkingDirectoryForLink(info2.absoluteFilePath());
+ QCOMPARE(QDir::fromNativeSeparators(wd), QDir::cleanPath(info1.absolutePath()));
+#endif
+
+ QVERIFY(QFile::remove(info2.absoluteFilePath()));
+}
+
+void tst_QFile::linkToDir()
+{
+#if defined(Q_OS_SYMBIAN)
+ QSKIP("Symbian does not support linking to directories", SkipAll);
+#endif
+ QFile::remove("myLinkToDir.lnk");
+ QDir dir;
+ dir.mkdir("myDir");
+ QFileInfo info1("myDir");
+ QVERIFY(QFile::link("myDir", "myLinkToDir.lnk"));
+ QFileInfo info2("myLinkToDir.lnk");
+#if !(defined Q_OS_HPUX && defined(__ia64))
+ // absurd HP-UX filesystem bug on gravlaks - checking if a symlink
+ // resolves or not alters the file system to make the broken symlink
+ // later fail...
+ QVERIFY(info2.isSymLink());
+#endif
+ QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath());
+ QVERIFY(QFile::remove(info2.absoluteFilePath()));
+ QFile::remove("myLinkToDir.lnk");
+ dir.rmdir("myDir");
+}
+
+void tst_QFile::absolutePathLinkToRelativePath()
+{
+#if defined(Q_OS_SYMBIAN)
+ QSKIP("Symbian does not support links", SkipAll);
+#endif
+ QFile::remove("myDir/test.txt");
+ QFile::remove("myDir/myLink.lnk");
+ QDir dir;
+ dir.mkdir("myDir");
+ QFile("myDir/test.txt").open(QFile::WriteOnly);
+
+#ifdef Q_OS_WIN
+ QVERIFY(QFile::link("test.txt", "myDir/myLink.lnk"));
+#else
+ QVERIFY(QFile::link("myDir/test.txt", "myDir/myLink.lnk"));
+#endif
+ QEXPECT_FAIL("", "Symlinking using relative paths is currently different on Windows and Unix/Symbian", Continue);
+ QCOMPARE(QFileInfo(QFile(QFileInfo("myDir/myLink.lnk").absoluteFilePath()).symLinkTarget()).absoluteFilePath(),
+ QFileInfo("myDir/test.txt").absoluteFilePath());
+
+ QFile::remove("myDir/test.txt");
+ QFile::remove("myDir/myLink.lnk");
+ dir.rmdir("myDir");
+}
+
+void tst_QFile::readBrokenLink()
+{
+#if defined(Q_OS_SYMBIAN)
+ QSKIP("Symbian does not support links", SkipAll);
+#endif
+ QFile::remove("myLink2.lnk");
+ QFileInfo info1("file12");
+#if defined(Q_OS_SYMBIAN)
+ // In Symbian can't link to nonexisting file directly, so create the file temporarily
+ QFile tempFile("file12");
+ tempFile.open(QIODevice::WriteOnly);
+ tempFile.link("myLink2.lnk");
+ tempFile.remove();
+#else
+ QVERIFY(QFile::link("file12", "myLink2.lnk"));
+#endif
+ QFileInfo info2("myLink2.lnk");
+ QVERIFY(info2.isSymLink());
+ QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath());
+ QVERIFY(QFile::remove(info2.absoluteFilePath()));
+
+#if !defined(Q_OS_SYMBIAN)
+ QVERIFY(QFile::link("ole/..", "myLink2.lnk"));
+ QCOMPARE(QFileInfo("myLink2.lnk").symLinkTarget(), QDir::currentPath());
+#endif
+}
+
+void tst_QFile::readTextFile_data()
+{
+ QTest::addColumn<QByteArray>("in");
+ QTest::addColumn<QByteArray>("out");
+
+ QTest::newRow("empty") << QByteArray() << QByteArray();
+ QTest::newRow("a") << QByteArray("a") << QByteArray("a");
+ QTest::newRow("a\\rb") << QByteArray("a\rb") << QByteArray("ab");
+ QTest::newRow("\\n") << QByteArray("\n") << QByteArray("\n");
+ QTest::newRow("\\r\\n") << QByteArray("\r\n") << QByteArray("\n");
+ QTest::newRow("\\r") << QByteArray("\r") << QByteArray();
+ QTest::newRow("twolines") << QByteArray("Hello\r\nWorld\r\n") << QByteArray("Hello\nWorld\n");
+ QTest::newRow("twolines no endline") << QByteArray("Hello\r\nWorld") << QByteArray("Hello\nWorld");
+}
+
+void tst_QFile::readTextFile()
+{
+ QFETCH(QByteArray, in);
+ QFETCH(QByteArray, out);
+
+ QFile winfile("winfile.txt");
+ QVERIFY(winfile.open(QFile::WriteOnly | QFile::Truncate));
+ winfile.write(in);
+ winfile.close();
+
+ QVERIFY(winfile.open(QFile::ReadOnly));
+ QCOMPARE(winfile.readAll(), in);
+ winfile.close();
+
+ QVERIFY(winfile.open(QFile::ReadOnly | QFile::Text));
+ QCOMPARE(winfile.readAll(), out);
+}
+
+void tst_QFile::readTextFile2()
+{
+ {
+ QFile file(SRCDIR "testlog.txt");
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ file.read(4097);
+ }
+
+ {
+ QFile file(SRCDIR "testlog.txt");
+ QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
+ file.read(4097);
+ }
+}
+
+void tst_QFile::writeTextFile_data()
+{
+ QTest::addColumn<QByteArray>("in");
+
+ QTest::newRow("empty") << QByteArray();
+ QTest::newRow("a") << QByteArray("a");
+ QTest::newRow("a\\rb") << QByteArray("a\rb");
+ QTest::newRow("\\n") << QByteArray("\n");
+ QTest::newRow("\\r\\n") << QByteArray("\r\n");
+ QTest::newRow("\\r") << QByteArray("\r");
+ QTest::newRow("twolines crlf") << QByteArray("Hello\r\nWorld\r\n");
+ QTest::newRow("twolines crlf no endline") << QByteArray("Hello\r\nWorld");
+ QTest::newRow("twolines lf") << QByteArray("Hello\nWorld\n");
+ QTest::newRow("twolines lf no endline") << QByteArray("Hello\nWorld");
+ QTest::newRow("mixed") << QByteArray("this\nis\r\na\nmixed\r\nfile\n");
+}
+
+void tst_QFile::writeTextFile()
+{
+ QFETCH(QByteArray, in);
+
+ QFile file("textfile.txt");
+ QVERIFY(file.open(QFile::WriteOnly | QFile::Truncate | QFile::Text));
+ QByteArray out = in;
+#ifdef Q_OS_WIN
+ out.replace('\n', "\r\n");
+#endif
+ QCOMPARE(file.write(in), qlonglong(in.size()));
+ file.close();
+
+ file.open(QFile::ReadOnly);
+ QCOMPARE(file.readAll(), out);
+}
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+void tst_QFile::largeUncFileSupport()
+{
+ qint64 size = Q_INT64_C(8589934592);
+ qint64 dataOffset = Q_INT64_C(8589914592);
+ QByteArray knownData("LargeFile content at offset 8589914592");
+ QString largeFile("//" + QtNetworkSettings::winServerName() + "/testsharelargefile/file.bin");
+
+ {
+ // 1) Native file handling.
+ QFile file(largeFile);
+ QCOMPARE(file.size(), size);
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QCOMPARE(file.size(), size);
+ QVERIFY(file.seek(dataOffset));
+ QCOMPARE(file.read(knownData.size()), knownData);
+ }
+ {
+ // 2) stdlib file handling.
+#if _MSC_VER <= 1310
+ QSKIP("platform SDK for MSVC 2003 does not support large files", SkipAll);
+#endif
+ QFile file;
+ FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb");
+ QVERIFY(file.open(fh, QIODevice::ReadOnly));
+ QCOMPARE(file.size(), size);
+ QVERIFY(file.seek(dataOffset));
+ QCOMPARE(file.read(knownData.size()), knownData);
+ fclose(fh);
+ }
+ {
+ // 3) stdio file handling.
+ QFile file;
+ FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb");
+ int fd = int(_fileno(fh));
+ QVERIFY(file.open(fd, QIODevice::ReadOnly));
+ QCOMPARE(file.size(), size);
+ QVERIFY(file.seek(dataOffset));
+ QCOMPARE(file.read(knownData.size()), knownData);
+ fclose(fh);
+ }
+}
+#endif
+
+void tst_QFile::tailFile()
+{
+ QSKIP("File change notifications are so far unsupported.", SkipAll);
+
+ QFile file("tail.txt");
+ QVERIFY(file.open(QFile::WriteOnly | QFile::Append));
+
+ QFile tailFile("tail.txt");
+ QVERIFY(tailFile.open(QFile::ReadOnly));
+ tailFile.seek(file.size());
+
+ QSignalSpy readSignal(&tailFile, SIGNAL(readyRead()));
+
+ file.write("", 1);
+
+ QTestEventLoop::instance().enterLoop(5);
+
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QCOMPARE(readSignal.count(), 1);
+}
+
+void tst_QFile::flush()
+{
+ QString fileName("stdfile.txt");
+
+ QFile::remove(fileName);
+
+ {
+ QFile file(fileName);
+ QVERIFY(file.open(QFile::WriteOnly));
+ QCOMPARE(file.write("abc", 3),qint64(3));
+ }
+
+ {
+ QFile file(fileName);
+ QVERIFY(file.open(QFile::WriteOnly | QFile::Append));
+ QCOMPARE(file.pos(), qlonglong(3));
+ QCOMPARE(file.write("def", 3), qlonglong(3));
+ QCOMPARE(file.pos(), qlonglong(6));
+ }
+
+ {
+ QFile file("stdfile.txt");
+ QVERIFY(file.open(QFile::ReadOnly));
+ QCOMPARE(file.readAll(), QByteArray("abcdef"));
+ }
+
+ QFile::remove(fileName);
+}
+
+void tst_QFile::bufferedRead()
+{
+ QFile::remove("stdfile.txt");
+
+ QFile file("stdfile.txt");
+ QVERIFY(file.open(QFile::WriteOnly));
+ file.write("abcdef");
+ file.close();
+
+#if defined(Q_OS_WINCE)
+ FILE *stdFile = fopen((QCoreApplication::applicationDirPath() + "/stdfile.txt").toAscii() , "r");
+#else
+ FILE *stdFile = fopen("stdfile.txt", "r");
+#endif
+ QVERIFY(stdFile);
+ char c;
+ QCOMPARE(int(fread(&c, 1, 1, stdFile)), 1);
+ QCOMPARE(c, 'a');
+ QCOMPARE(int(ftell(stdFile)), 1);
+
+ {
+ QFile file;
+ QVERIFY(file.open(stdFile, QFile::ReadOnly));
+ QCOMPARE(file.pos(), qlonglong(1));
+ QCOMPARE(file.read(&c, 1), qlonglong(1));
+ QCOMPARE(c, 'b');
+ QCOMPARE(file.pos(), qlonglong(2));
+ }
+
+ fclose(stdFile);
+}
+
+void tst_QFile::isSequential()
+{
+#if defined (Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ QSKIP("Unix only test.", SkipAll);
+#endif
+
+ QFile zero("/dev/null");
+ QVERIFY(zero.open(QFile::ReadOnly));
+ QVERIFY(zero.isSequential());
+}
+
+void tst_QFile::encodeName()
+{
+ QCOMPARE(QFile::encodeName(QString::null), QByteArray());
+}
+
+void tst_QFile::truncate()
+{
+ for (int i = 0; i < 2; ++i) {
+ QFile file("truncate.txt");
+ QVERIFY(file.open(QFile::WriteOnly));
+ file.write(QByteArray(200, '@'));
+ file.close();
+
+ QVERIFY(file.open((i ? QFile::WriteOnly : QFile::ReadWrite) | QFile::Truncate));
+ file.write(QByteArray(100, '$'));
+ file.close();
+
+ QVERIFY(file.open(QFile::ReadOnly));
+ QCOMPARE(file.readAll(), QByteArray(100, '$'));
+ }
+}
+
+void tst_QFile::seekToPos()
+{
+ {
+ QFile file("seekToPos.txt");
+ QVERIFY(file.open(QFile::WriteOnly));
+ file.write("a\r\nb\r\nc\r\n");
+ file.flush();
+ }
+
+ QFile file("seekToPos.txt");
+ QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
+ file.seek(1);
+ char c;
+ QVERIFY(file.getChar(&c));
+ QCOMPARE(c, '\n');
+
+ QCOMPARE(file.pos(), qint64(3));
+ file.seek(file.pos());
+ QCOMPARE(file.pos(), qint64(3));
+
+ file.seek(1);
+ file.seek(file.pos());
+ QCOMPARE(file.pos(), qint64(1));
+
+}
+
+void tst_QFile::seekAfterEndOfFile()
+{
+ QLatin1String filename("seekAfterEof.dat");
+ QFile::remove(filename);
+ {
+ QFile file(filename);
+ QVERIFY(file.open(QFile::WriteOnly));
+ file.write("abcd");
+ QCOMPARE(file.size(), qint64(4));
+ file.seek(8);
+ file.write("ijkl");
+ QCOMPARE(file.size(), qint64(12));
+ file.seek(4);
+ file.write("efgh");
+ QCOMPARE(file.size(), qint64(12));
+ file.seek(16);
+ file.write("----");
+ QCOMPARE(file.size(), qint64(20));
+ file.flush();
+ }
+
+ QFile file(filename);
+ QVERIFY(file.open(QFile::ReadOnly));
+ QByteArray contents = file.readAll();
+ QCOMPARE(contents.left(12), QByteArray("abcdefghijkl", 12));
+ //bytes 12-15 are uninitialised so we don't care what they read as.
+ QCOMPARE(contents.mid(16), QByteArray("----", 4));
+ file.close();
+ QFile::remove(filename);
+}
+
+void tst_QFile::FILEReadWrite()
+{
+ // Tests modifying a file. First creates it then reads in 4 bytes and then overwrites these
+ // 4 bytes with new values. At the end check to see the file contains the new values.
+
+ QFile::remove("FILEReadWrite.txt");
+
+ // create test file
+ {
+ QFile f("FILEReadWrite.txt");
+ QVERIFY(f.open(QFile::WriteOnly));
+ QDataStream ds(&f);
+ qint8 c = 0;
+ ds << c;
+ c = 1;
+ ds << c;
+ c = 2;
+ ds << c;
+ c = 3;
+ ds << c;
+ c = 4;
+ ds << c;
+ c = 5;
+ ds << c;
+ c = 6;
+ ds << c;
+ c = 7;
+ ds << c;
+ c = 8;
+ ds << c;
+ c = 9;
+ ds << c;
+ c = 10;
+ ds << c;
+ c = 11;
+ ds << c;
+ f.close();
+ }
+
+#ifdef Q_OS_WINCE
+ FILE *fp = fopen(qPrintable(QCoreApplication::applicationDirPath() + "\\FILEReadWrite.txt"), "r+b");
+#else
+ FILE *fp = fopen("FILEReadWrite.txt", "r+b");
+#endif
+ QVERIFY(fp);
+ QFile file;
+ QVERIFY(file.open(fp, QFile::ReadWrite));
+ QDataStream sfile(&file) ;
+
+ qint8 var1,var2,var3,var4;
+ while (!sfile.atEnd())
+ {
+ qint64 base = file.pos();
+
+ QCOMPARE(file.pos(), base + 0);
+ sfile >> var1;
+ QCOMPARE(file.pos(), base + 1);
+ file.flush(); // flushing should not change the base
+ QCOMPARE(file.pos(), base + 1);
+ sfile >> var2;
+ QCOMPARE(file.pos(), base + 2);
+ sfile >> var3;
+ QCOMPARE(file.pos(), base + 3);
+ sfile >> var4;
+ QCOMPARE(file.pos(), base + 4);
+ file.seek(file.pos() - 4) ; // Move it back 4, for we are going to write new values based on old ones
+ QCOMPARE(file.pos(), base + 0);
+ sfile << qint8(var1 + 5);
+ QCOMPARE(file.pos(), base + 1);
+ sfile << qint8(var2 + 5);
+ QCOMPARE(file.pos(), base + 2);
+ sfile << qint8(var3 + 5);
+ QCOMPARE(file.pos(), base + 3);
+ sfile << qint8(var4 + 5);
+ QCOMPARE(file.pos(), base + 4);
+
+ }
+ file.close();
+ fclose(fp);
+
+ // check modified file
+ {
+ QFile f("FILEReadWrite.txt");
+ QVERIFY(f.open(QFile::ReadOnly));
+ QDataStream ds(&f);
+ qint8 c = 0;
+ ds >> c;
+ QCOMPARE(c, (qint8)5);
+ ds >> c;
+ QCOMPARE(c, (qint8)6);
+ ds >> c;
+ QCOMPARE(c, (qint8)7);
+ ds >> c;
+ QCOMPARE(c, (qint8)8);
+ ds >> c;
+ QCOMPARE(c, (qint8)9);
+ ds >> c;
+ QCOMPARE(c, (qint8)10);
+ ds >> c;
+ QCOMPARE(c, (qint8)11);
+ ds >> c;
+ QCOMPARE(c, (qint8)12);
+ ds >> c;
+ QCOMPARE(c, (qint8)13);
+ ds >> c;
+ QCOMPARE(c, (qint8)14);
+ ds >> c;
+ QCOMPARE(c, (qint8)15);
+ ds >> c;
+ QCOMPARE(c, (qint8)16);
+ f.close();
+ }
+
+ QFile::remove("FILEReadWrite.txt");
+}
+
+
+/*
+#include <qglobal.h>
+#define BUFFSIZE 1
+#define FILESIZE 0x10000000f
+void tst_QFile::largeFileSupport()
+{
+#ifdef Q_OS_SOLARIS
+ QSKIP("Solaris does not support statfs", SkipAll);
+#else
+ qlonglong sizeNeeded = 2147483647;
+ sizeNeeded *= 2;
+ sizeNeeded += 1024;
+ qlonglong freespace = qlonglong(0);
+#ifdef Q_WS_WIN
+ _ULARGE_INTEGER free;
+ if (::GetDiskFreeSpaceEx((wchar_t*)QDir::currentPath().utf16(), &free, 0, 0))
+ freespace = free.QuadPart;
+ if (freespace != 0) {
+#elif defined(Q_OS_IRIX)
+ struct statfs info;
+ if (statfs(QDir::currentPath().local8Bit(), &info, sizeof(struct statfs), 0) == 0) {
+ freespace = qlonglong(info.f_bfree * info.f_bsize);
+#else
+ struct statfs info;
+ if (statfs(const_cast<char *>(QDir::currentPath().toLocal8Bit().constData()), &info) == 0) {
+ freespace = qlonglong(info.f_bavail * info.f_bsize);
+#endif
+ if (freespace > sizeNeeded) {
+ QFile bigFile("bigfile");
+ if (bigFile.open(QFile::ReadWrite)) {
+ char c[BUFFSIZE] = {'a'};
+ QVERIFY(bigFile.write(c, BUFFSIZE) == BUFFSIZE);
+ qlonglong oldPos = bigFile.pos();
+ QVERIFY(bigFile.resize(sizeNeeded));
+ QCOMPARE(oldPos, bigFile.pos());
+ QVERIFY(bigFile.seek(sizeNeeded - BUFFSIZE));
+ QVERIFY(bigFile.write(c, BUFFSIZE) == BUFFSIZE);
+
+ bigFile.close();
+ if (bigFile.open(QFile::ReadOnly)) {
+ QVERIFY(bigFile.read(c, BUFFSIZE) == BUFFSIZE);
+ int i = 0;
+ for (i=0; i<BUFFSIZE; i++)
+ QCOMPARE(c[i], 'a');
+ QVERIFY(bigFile.seek(sizeNeeded - BUFFSIZE));
+ QVERIFY(bigFile.read(c, BUFFSIZE) == BUFFSIZE);
+ for (i=0; i<BUFFSIZE; i++)
+ QCOMPARE(c[i], 'a');
+ bigFile.close();
+ QVERIFY(bigFile.remove());
+ } else {
+ QVERIFY(bigFile.remove());
+ QFAIL("Could not reopen file");
+ }
+ } else {
+ QFAIL("Could not open file");
+ }
+ } else {
+ QSKIP("Not enough space to run test", SkipSingle);
+ }
+ } else {
+ QFAIL("Could not determin disk space");
+ }
+#endif
+}
+*/
+
+void tst_QFile::i18nFileName_data()
+{
+ QTest::addColumn<QString>("fileName");
+
+ QTest::newRow( "01" ) << QString::fromUtf8("xxxxxxx.txt");
+}
+
+void tst_QFile::i18nFileName()
+{
+ QFETCH(QString, fileName);
+ if (QFile::exists(fileName)) {
+ QVERIFY(QFile::remove(fileName));
+ }
+ {
+ QFile file(fileName);
+ QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
+ QTextStream ts(&file);
+ ts.setCodec("UTF-8");
+ ts << fileName << endl;
+ }
+ {
+ QFile file(fileName);
+ QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
+ QTextStream ts(&file);
+ ts.setCodec("UTF-8");
+ QString line = ts.readLine();
+ QCOMPARE(line, fileName);
+ }
+ QVERIFY(QFile::remove(fileName));
+}
+
+
+void tst_QFile::longFileName_data()
+{
+ QTest::addColumn<QString>("fileName");
+
+ QTest::newRow( "16 chars" ) << QString::fromLatin1("longFileName.txt");
+ QTest::newRow( "52 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName.txt");
+ QTest::newRow( "148 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName.txt");
+ QTest::newRow( "244 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName.txt");
+ QTest::newRow( "244 chars to absolutepath" ) << QFileInfo(QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName.txt")).absoluteFilePath();
+ /* needs to be put on a windows 2000 > test machine
+ QTest::newRow( "244 chars on UNC" ) << QString::fromLatin1("//arsia/D/troll/tmp/longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName"
+ "longFileNamelongFileNamelongFileNamelongFileName.txt");*/
+}
+
+void tst_QFile::longFileName()
+{
+ QFETCH(QString, fileName);
+ if (QFile::exists(fileName)) {
+ QVERIFY(QFile::remove(fileName));
+ }
+ {
+ QFile file(fileName);
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QEXPECT_FAIL("244 chars", "Full pathname must be less than 260 chars", Abort);
+ QEXPECT_FAIL("244 chars to absolutepath", "Full pathname must be less than 260 chars", Abort);
+#endif
+ QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
+ QTextStream ts(&file);
+ ts << fileName << endl;
+ }
+ {
+ QFile file(fileName);
+ QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
+ QTextStream ts(&file);
+ QString line = ts.readLine();
+ QCOMPARE(line, fileName);
+ }
+ QString newName = fileName + QLatin1String("1");
+ {
+ QVERIFY(QFile::copy(fileName, newName));
+ QFile file(newName);
+ QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
+ QTextStream ts(&file);
+ QString line = ts.readLine();
+ QCOMPARE(line, fileName);
+
+ }
+ QVERIFY(QFile::remove(newName));
+ {
+ QVERIFY(QFile::rename(fileName, newName));
+ QFile file(newName);
+ QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
+ QTextStream ts(&file);
+ QString line = ts.readLine();
+ QCOMPARE(line, fileName);
+ }
+ QVERIFY(QFile::exists(newName));
+ QVERIFY(QFile::remove(newName));
+}
+
+class MyEngine : public QAbstractFileEngine
+{
+public:
+ MyEngine(int n) { number = n; }
+ virtual ~MyEngine() {}
+
+ void setFileName(const QString &) {}
+ bool open(int ) { return false; }
+ bool close() { return false; }
+ bool flush() { return false; }
+ qint64 size() const { return 123 + number; }
+ qint64 at() const { return -1; }
+ bool seek(qint64) { return false; }
+ bool isSequential() const { return false; }
+ qint64 read(char *, qint64) { return -1; }
+ qint64 write(const char *, qint64) { return -1; }
+ bool remove() { return false; }
+ bool copy(const QString &) { return false; }
+ bool rename(const QString &) { return false; }
+ bool link(const QString &) { return false; }
+ bool mkdir(const QString &, bool) const { return false; }
+ bool rmdir(const QString &, bool) const { return false; }
+ bool setSize(qint64) { return false; }
+ QStringList entryList(QDir::Filters, const QStringList &) const { return QStringList(); }
+ bool caseSensitive() const { return false; }
+ bool isRelativePath() const { return false; }
+ FileFlags fileFlags(FileFlags) const { return 0; }
+ bool chmod(uint) { return false; }
+ QString fileName(FileName) const { return name; }
+ uint ownerId(FileOwner) const { return 0; }
+ QString owner(FileOwner) const { return QString(); }
+ QDateTime fileTime(FileTime) const { return QDateTime(); }
+
+private:
+ int number;
+ QString name;
+};
+
+class MyHandler : public QAbstractFileEngineHandler
+{
+public:
+ inline QAbstractFileEngine *create(const QString &) const
+ {
+ return new MyEngine(1);
+ }
+};
+
+class MyHandler2 : public QAbstractFileEngineHandler
+{
+public:
+ inline QAbstractFileEngine *create(const QString &) const
+ {
+ return new MyEngine(2);
+ }
+};
+
+void tst_QFile::fileEngineHandler()
+{
+ // A file that does not exist has a size of 0.
+ QFile::remove("ole.bull");
+ QFile file("ole.bull");
+ QCOMPARE(file.size(), qint64(0));
+
+ // Instantiating our handler will enable the new engine.
+ MyHandler handler;
+ file.setFileName("ole.bull");
+ QCOMPARE(file.size(), qint64(124));
+
+ // A new, identical handler should take preference over the last one.
+ MyHandler2 handler2;
+ file.setFileName("ole.bull");
+ QCOMPARE(file.size(), qint64(125));
+
+}
+
+class MyRecursiveHandler : public QAbstractFileEngineHandler
+{
+public:
+ inline QAbstractFileEngine *create(const QString &fileName) const
+ {
+ if (fileName.startsWith(":!")) {
+ QDir dir;
+ QString realFile = SRCDIR + fileName.mid(2);
+ if (dir.exists(realFile))
+ return new QFSFileEngine(realFile);
+ }
+ return 0;
+ }
+};
+
+void tst_QFile::useQFileInAFileHandler()
+{
+ // This test should not dead-lock
+ MyRecursiveHandler handler;
+ QFile file(":!tst_qfile.cpp");
+ QVERIFY(file.exists());
+}
+
+void tst_QFile::getCharFF()
+{
+ QFile file("file.txt");
+ file.open(QFile::ReadWrite);
+ file.write("\xff\xff\xff");
+ file.flush();
+ file.seek(0);
+
+ char c;
+ QVERIFY(file.getChar(&c));
+ QVERIFY(file.getChar(&c));
+ QVERIFY(file.getChar(&c));
+}
+
+void tst_QFile::remove_and_exists()
+{
+ QFile::remove("tull_i_grunn.txt");
+ QFile f("tull_i_grunn.txt");
+
+ QVERIFY(!f.exists());
+
+ bool opened = f.open(QIODevice::WriteOnly);
+ QVERIFY(opened);
+
+ f.write(QString("testing that remove/exists work...").toLatin1());
+ f.close();
+
+ QVERIFY(f.exists());
+
+ f.remove();
+ QVERIFY(!f.exists());
+}
+
+void tst_QFile::removeOpenFile()
+{
+ {
+ // remove an opened, write-only file
+ QFile::remove("remove_unclosed.txt");
+ QFile f("remove_unclosed.txt");
+
+ QVERIFY(!f.exists());
+ bool opened = f.open(QIODevice::WriteOnly);
+ QVERIFY(opened);
+ f.write(QString("testing that remove closes the file first...").toLatin1());
+
+ bool removed = f.remove(); // remove should both close and remove the file
+ QVERIFY(removed);
+ QVERIFY(!f.isOpen());
+ QVERIFY(!f.exists());
+ QVERIFY(f.error() == QFile::NoError);
+ }
+
+ {
+ // remove an opened, read-only file
+ QFile::remove("remove_unclosed.txt");
+
+ // first, write a file that we can remove
+ {
+ QFile f("remove_unclosed.txt");
+ QVERIFY(!f.exists());
+ bool opened = f.open(QIODevice::WriteOnly);
+ QVERIFY(opened);
+ f.write(QString("testing that remove closes the file first...").toLatin1());
+ f.close();
+ }
+
+ QFile f("remove_unclosed.txt");
+ bool opened = f.open(QIODevice::ReadOnly);
+ QVERIFY(opened);
+ f.readAll();
+ // this used to only fail on FreeBSD (and Mac OS X)
+ QVERIFY(f.flush());
+ bool removed = f.remove(); // remove should both close and remove the file
+ QVERIFY(removed);
+ QVERIFY(!f.isOpen());
+ QVERIFY(!f.exists());
+ QVERIFY(f.error() == QFile::NoError);
+ }
+}
+
+void tst_QFile::fullDisk()
+{
+ QFile file("/dev/full");
+ if (!file.exists())
+ QSKIP("/dev/full doesn't exist on this system", SkipAll);
+
+ QVERIFY(file.open(QIODevice::WriteOnly));
+ file.write("foobar", 6);
+
+ QVERIFY(!file.flush());
+ QCOMPARE(file.error(), QFile::ResourceError);
+ QVERIFY(!file.flush());
+ QCOMPARE(file.error(), QFile::ResourceError);
+
+ char c = 0;
+ file.write(&c, 0);
+ QVERIFY(!file.flush());
+ QCOMPARE(file.error(), QFile::ResourceError);
+ QCOMPARE(file.write(&c, 1), qint64(1));
+ QVERIFY(!file.flush());
+ QCOMPARE(file.error(), QFile::ResourceError);
+
+ file.close();
+ QVERIFY(!file.isOpen());
+ QCOMPARE(file.error(), QFile::ResourceError);
+
+ file.open(QIODevice::WriteOnly);
+ QCOMPARE(file.error(), QFile::NoError);
+ QVERIFY(file.flush()); // Shouldn't inherit write buffer
+ file.close();
+ QCOMPARE(file.error(), QFile::NoError);
+
+ // try again without flush:
+ QVERIFY(file.open(QIODevice::WriteOnly));
+ file.write("foobar", 6);
+ file.close();
+ QVERIFY(file.error() != QFile::NoError);
+}
+
+void tst_QFile::writeLargeDataBlock_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<int>("type");
+
+ QTest::newRow("localfile-QFile") << "./largeblockfile.txt" << (int)OpenQFile;
+ QTest::newRow("localfile-Fd") << "./largeblockfile.txt" << (int)OpenFd;
+ QTest::newRow("localfile-Stream") << "./largeblockfile.txt" << (int)OpenStream;
+#ifdef Q_OS_SYMBIAN
+ QTest::newRow("localfile-RFile") << "./largeblockfile.txt" << (int)OpenRFile;
+#endif
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ // Some semi-randomness to avoid collisions.
+ QTest::newRow("unc file")
+ << QString("//" + QtNetworkSettings::winServerName() + "/TESTSHAREWRITABLE/largefile-%1-%2.txt")
+ .arg(QHostInfo::localHostName())
+ .arg(QTime::currentTime().msec()) << (int)OpenQFile;
+#endif
+}
+
+static QByteArray getLargeDataBlock()
+{
+ static QByteArray array;
+
+ if (array.isNull())
+ {
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ int resizeSize = 1024 * 1024; // WinCE and Symbian do not have much space
+#else
+ int resizeSize = 64 * 1024 * 1024;
+#endif
+ array.resize(resizeSize);
+ for (int i = 0; i < array.size(); ++i)
+ array[i] = uchar(i);
+ }
+
+ return array;
+}
+
+void tst_QFile::writeLargeDataBlock()
+{
+ QFETCH(QString, fileName);
+ QFETCH( int, type );
+
+ QByteArray const originalData = getLargeDataBlock();
+
+ {
+ QFile file(fileName);
+
+ QVERIFY2( openFile(file, QIODevice::WriteOnly, (FileType)type),
+ qPrintable(QString("Couldn't open file for writing: [%1]").arg(fileName)) );
+ QCOMPARE( file.write(originalData), (qint64)originalData.size() );
+ QVERIFY( file.flush() );
+
+ closeFile(file);
+ }
+
+ QByteArray readData;
+
+ {
+ QFile file(fileName);
+
+ QVERIFY2( openFile(file, QIODevice::ReadOnly, (FileType)type),
+ qPrintable(QString("Couldn't open file for reading: [%1]").arg(fileName)) );
+ readData = file.readAll();
+ closeFile(file);
+ }
+
+ QCOMPARE( readData, originalData );
+ QVERIFY( QFile::remove(fileName) );
+}
+
+void tst_QFile::readFromWriteOnlyFile()
+{
+ QFile file("writeonlyfile");
+ QVERIFY(file.open(QFile::WriteOnly));
+ char c;
+ QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device");
+ QCOMPARE(file.read(&c, 1), qint64(-1));
+}
+
+void tst_QFile::writeToReadOnlyFile()
+{
+ QFile file("readonlyfile");
+ QVERIFY(file.open(QFile::ReadOnly));
+ char c = 0;
+ QTest::ignoreMessage(QtWarningMsg, "QIODevice::write: ReadOnly device");
+ QCOMPARE(file.write(&c, 1), qint64(-1));
+}
+
+void tst_QFile::virtualFile()
+{
+ // test if QFile works with virtual files
+ QString fname;
+#if defined(Q_OS_LINUX)
+ fname = "/proc/self/maps";
+#elif defined(Q_OS_AIX)
+ fname = QString("/proc/%1/map").arg(getpid());
+#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
+ fname = "/proc/curproc/map";
+#else
+ QSKIP("This platform does not have 0-sized virtual files", SkipAll);
+#endif
+
+ // consistency check
+ QFileInfo fi(fname);
+ QVERIFY(fi.exists());
+ QVERIFY(fi.isFile());
+ QCOMPARE(fi.size(), Q_INT64_C(0));
+
+ // open the file
+ QFile f(fname);
+ QVERIFY(f.open(QIODevice::ReadOnly));
+ QCOMPARE(f.size(), Q_INT64_C(0));
+ QVERIFY(f.atEnd());
+
+ // read data
+ QByteArray data = f.read(16);
+ QCOMPARE(data.size(), 16);
+ QCOMPARE(f.pos(), Q_INT64_C(16));
+
+ // line-reading
+ data = f.readLine();
+ QVERIFY(!data.isEmpty());
+
+ // read all:
+ data = f.readAll();
+ QVERIFY(f.pos() != 0);
+ QVERIFY(!data.isEmpty());
+
+ // seeking
+ QVERIFY(f.seek(1));
+ QCOMPARE(f.pos(), Q_INT64_C(1));
+}
+
+void tst_QFile::textFile()
+{
+#if defined(Q_OS_WINCE)
+ FILE *fs = ::fopen((QCoreApplication::applicationDirPath() + "/writeabletextfile").toAscii() , "wt");
+#elif defined(Q_OS_WIN)
+ FILE *fs = ::fopen("writeabletextfile", "wt");
+#else
+ FILE *fs = ::fopen("writeabletextfile", "w");
+#endif
+ QFile f;
+ QByteArray part1("This\nis\na\nfile\nwith\nnewlines\n");
+ QByteArray part2("Add\nsome\nmore\nnewlines\n");
+
+ QVERIFY(f.open(fs, QIODevice::WriteOnly));
+ f.write(part1);
+ f.write(part2);
+ f.close();
+ ::fclose(fs);
+
+ QFile file("writeabletextfile");
+ QVERIFY(file.open(QIODevice::ReadOnly));
+
+ QByteArray data = file.readAll();
+
+ QByteArray expected = part1 + part2;
+#ifdef Q_OS_WIN
+ expected.replace("\n", "\015\012");
+#endif
+ QCOMPARE(data, expected);
+ file.close();
+ file.remove();
+}
+
+void tst_QFile::rename_data()
+{
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<QString>("destination");
+ QTest::addColumn<bool>("result");
+
+ QTest::newRow("a -> b") << QString("a") << QString("b") << false;
+ QTest::newRow("a -> .") << QString("a") << QString(".") << false;
+ QTest::newRow("renamefile -> renamefile") << QString("renamefile") << QString("renamefile") << false;
+ QTest::newRow("renamefile -> noreadfile") << QString("renamefile") << QString("noreadfile") << false;
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ QTest::newRow("renamefile -> /etc/renamefile") << QString("renamefile") << QString("/etc/renamefile") << false;
+#endif
+ QTest::newRow("renamefile -> renamedfile") << QString("renamefile") << QString("renamedfile") << true;
+ QTest::newRow("renamefile -> ..") << QString("renamefile") << QString("..") << false;
+}
+
+void tst_QFile::rename()
+{
+ QFETCH(QString, source);
+ QFETCH(QString, destination);
+ QFETCH(bool, result);
+
+ QFile::remove("renamedfile");
+ QFile f("renamefile");
+ f.open(QFile::WriteOnly);
+ f.close();
+
+ QFile file(source);
+ QCOMPARE(file.rename(destination), result);
+
+ if (result)
+ QCOMPARE(file.error(), QFile::NoError);
+ else
+ QCOMPARE(file.error(), QFile::RenameError);
+
+ QFile::remove("renamefile");
+}
+
+/*!
+ \since 4.5
+
+ Some special files have QFile::atEnd() returning true, even though there is
+ more data available. True for corner cases, as well as some mounts on OS X.
+
+ Here, we reproduce that condition by having a QFile sub-class with this
+ peculiar atEnd() behavior.
+
+ See task 231583.
+ */
+void tst_QFile::renameWithAtEndSpecialFile() const
+{
+ class PeculiarAtEnd : public QFile
+ {
+ public:
+ virtual bool atEnd() const
+ {
+ return true;
+ }
+ };
+
+ const QString newName(QLatin1String("newName.txt"));
+ /* Cleanup, so we're a bit more robust. */
+ QFile::remove(newName);
+
+ const QString originalName(QString(SRCDIR "forRenaming.txt"));
+
+ PeculiarAtEnd file;
+ file.setFileName(originalName);
+ QVERIFY(file.open(QIODevice::ReadOnly));
+
+ QVERIFY(file.rename(newName));
+
+ file.close();
+ /* Guess what, we have to rename it back, otherwise we'll fail on second
+ * invocation. */
+ QVERIFY(QFile::rename(newName, originalName));
+}
+
+void tst_QFile::renameFallback()
+{
+ // Using a resource file both to trigger QFile::rename's fallback handling
+ // and as a *read-only* source whose move should fail.
+ QFile file(":/rename-fallback.qrc");
+ QVERIFY(file.exists() && "(test-precondition)");
+ QFile::remove("file-rename-destination.txt");
+
+ QVERIFY(!file.rename("file-rename-destination.txt"));
+ QVERIFY(!QFile::exists("file-rename-destination.txt"));
+ QVERIFY(!file.isOpen());
+}
+
+void tst_QFile::renameMultiple()
+{
+ // create the file if it doesn't exist
+ QFile file("file-to-be-renamed.txt");
+ QFile file2("existing-file.txt");
+ QVERIFY(file.open(QIODevice::ReadWrite) && "(test-precondition)");
+ QVERIFY(file2.open(QIODevice::ReadWrite) && "(test-precondition)");
+
+ // any stale files from previous test failures?
+ QFile::remove("file-renamed-once.txt");
+ QFile::remove("file-renamed-twice.txt");
+
+ // begin testing
+ QVERIFY(QFile::exists("existing-file.txt"));
+ QVERIFY(!file.rename("existing-file.txt"));
+ QCOMPARE(file.error(), QFile::RenameError);
+ QCOMPARE(file.fileName(), QString("file-to-be-renamed.txt"));
+
+ QVERIFY(file.rename("file-renamed-once.txt"));
+ QVERIFY(!file.isOpen());
+ QCOMPARE(file.fileName(), QString("file-renamed-once.txt"));
+
+ QVERIFY(QFile::exists("existing-file.txt"));
+ QVERIFY(!file.rename("existing-file.txt"));
+ QCOMPARE(file.error(), QFile::RenameError);
+ QCOMPARE(file.fileName(), QString("file-renamed-once.txt"));
+
+ QVERIFY(file.rename("file-renamed-twice.txt"));
+ QVERIFY(!file.isOpen());
+ QCOMPARE(file.fileName(), QString("file-renamed-twice.txt"));
+
+ QVERIFY(QFile::exists("existing-file.txt"));
+ QVERIFY(!QFile::exists("file-to-be-renamed.txt"));
+ QVERIFY(!QFile::exists("file-renamed-once.txt"));
+ QVERIFY(QFile::exists("file-renamed-twice.txt"));
+
+ file.remove();
+ file2.remove();
+ QVERIFY(!QFile::exists("file-renamed-twice.txt"));
+ QVERIFY(!QFile::exists("existing-file.txt"));
+}
+
+void tst_QFile::appendAndRead()
+{
+ QFile writeFile(QLatin1String("appendfile.txt"));
+ QVERIFY(writeFile.open(QIODevice::WriteOnly | QIODevice::Truncate));
+
+ QFile readFile(QLatin1String("appendfile.txt"));
+ QVERIFY(readFile.open(QIODevice::ReadOnly));
+
+ // Write to the end of the file, then read that character back, and so on.
+ for (int i = 0; i < 100; ++i) {
+ char c = '\0';
+ writeFile.putChar(char(i % 256));
+ writeFile.flush();
+ QVERIFY(readFile.getChar(&c));
+ QCOMPARE(c, char(i % 256));
+ QCOMPARE(readFile.pos(), writeFile.pos());
+ }
+
+ // Write blocks and read them back
+ for (int j = 0; j < 18; ++j) {
+ writeFile.write(QByteArray(1 << j, '@'));
+ writeFile.flush();
+ QCOMPARE(readFile.read(1 << j).size(), 1 << j);
+ }
+
+ readFile.close();
+ QFile::remove(QLatin1String("appendfile.txt"));
+}
+
+void tst_QFile::miscWithUncPathAsCurrentDir()
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ QString current = QDir::currentPath();
+ QVERIFY(QDir::setCurrent("//" + QtNetworkSettings::winServerName() + "/testshare"));
+ QFile file("test.pri");
+ QVERIFY(file.exists());
+ QCOMPARE(int(file.size()), 34);
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QVERIFY(QDir::setCurrent(current));
+#endif
+}
+
+void tst_QFile::standarderror()
+{
+ QFile f;
+ bool ok = f.open(stderr, QFile::WriteOnly);
+ QVERIFY(ok);
+ f.close();
+}
+
+void tst_QFile::handle()
+{
+ int fd;
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
+ QFile file(SRCDIR "tst_qfile.cpp");
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ fd = int(file.handle());
+ QVERIFY(fd > 2);
+ QCOMPARE(int(file.handle()), fd);
+ char c = '\0';
+ QT_READ(int(file.handle()), &c, 1);
+ QCOMPARE(c, '/');
+
+ // test if the QFile and the handle remain in sync
+ QVERIFY(file.getChar(&c));
+ QCOMPARE(c, '*');
+
+ // same, but read from QFile first now
+ file.close();
+ QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered));
+ fd = int(file.handle());
+ QVERIFY(fd > 2);
+ QVERIFY(file.getChar(&c));
+ QCOMPARE(c, '/');
+#ifdef Q_OS_UNIX
+ QCOMPARE(QT_READ(fd, &c, 1), ssize_t(1));
+#else
+ QCOMPARE(QT_READ(fd, &c, 1), 1);
+#endif
+
+ QCOMPARE(c, '*');
+#endif
+
+ //test round trip of adopted stdio file handle
+ QFile file2;
+ FILE *fp = fopen(SRCDIR "tst_qfile.cpp", "r");
+ file2.open(fp, QIODevice::ReadOnly);
+ QCOMPARE(int(file2.handle()), int(fileno(fp)));
+ QCOMPARE(int(file2.handle()), int(fileno(fp)));
+ fclose(fp);
+
+ //test round trip of adopted posix file handle
+#ifdef Q_OS_UNIX
+ QFile file3;
+ fd = QT_OPEN(SRCDIR "tst_qfile.cpp", QT_OPEN_RDONLY);
+ file3.open(fd, QIODevice::ReadOnly);
+ QCOMPARE(int(file3.handle()), fd);
+ QT_CLOSE(fd);
+#endif
+}
+
+void tst_QFile::nativeHandleLeaks()
+{
+#ifdef Q_OS_SYMBIAN
+ QSKIP("test assumptions invalid for symbian", SkipAll);
+#else
+ int fd1, fd2;
+
+#ifdef Q_OS_WIN
+ HANDLE handle1, handle2;
+#endif
+
+ {
+ QFile file("qt_file.tmp");
+ QVERIFY( file.open(QIODevice::ReadWrite) );
+
+ fd1 = file.handle();
+ QVERIFY( -1 != fd1 );
+ }
+
+#ifdef Q_OS_WIN
+ handle1 = ::CreateFileA("qt_file.tmp", GENERIC_READ, 0, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ QVERIFY( INVALID_HANDLE_VALUE != handle1 );
+ QVERIFY( ::CloseHandle(handle1) );
+#endif
+
+ {
+ QFile file("qt_file.tmp");
+ QVERIFY( file.open(QIODevice::ReadOnly) );
+
+ fd2 = file.handle();
+ QVERIFY( -1 != fd2 );
+ }
+
+#ifdef Q_OS_WIN
+ handle2 = ::CreateFileA("qt_file.tmp", GENERIC_READ, 0, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ QVERIFY( INVALID_HANDLE_VALUE != handle2 );
+ QVERIFY( ::CloseHandle(handle2) );
+#endif
+
+ QCOMPARE( fd2, fd1 );
+
+#ifdef Q_OS_WIN
+ QCOMPARE( handle2, handle1 );
+#endif
+#endif
+}
+
+void tst_QFile::readEof_data()
+{
+ QTest::addColumn<QString>("filename");
+ QTest::addColumn<int>("imode");
+
+ QTest::newRow("buffered") << SRCDIR "testfile.txt" << 0;
+ QTest::newRow("unbuffered") << SRCDIR "testfile.txt" << int(QIODevice::Unbuffered);
+
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ QTest::newRow("sequential,buffered") << "/dev/null" << 0;
+ QTest::newRow("sequential,unbuffered") << "/dev/null" << int(QIODevice::Unbuffered);
+#endif
+}
+
+void tst_QFile::readEof()
+{
+ QFETCH(QString, filename);
+ QFETCH(int, imode);
+ QIODevice::OpenMode mode = QIODevice::OpenMode(imode);
+
+ {
+ QFile file(filename);
+ QVERIFY(file.open(QIODevice::ReadOnly | mode));
+ bool isSequential = file.isSequential();
+ if (!isSequential) {
+ QVERIFY(file.seek(245));
+ QVERIFY(file.atEnd());
+ }
+
+ char buf[10];
+ int ret = file.read(buf, sizeof buf);
+ QCOMPARE(ret, 0);
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+
+ // Do it again to ensure that we get the same result
+ ret = file.read(buf, sizeof buf);
+ QCOMPARE(ret, 0);
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+ }
+
+ {
+ QFile file(filename);
+ QVERIFY(file.open(QIODevice::ReadOnly | mode));
+ bool isSequential = file.isSequential();
+ if (!isSequential) {
+ QVERIFY(file.seek(245));
+ QVERIFY(file.atEnd());
+ }
+
+ QByteArray ret = file.read(10);
+ QVERIFY(ret.isEmpty());
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+
+ // Do it again to ensure that we get the same result
+ ret = file.read(10);
+ QVERIFY(ret.isEmpty());
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+ }
+
+ {
+ QFile file(filename);
+ QVERIFY(file.open(QIODevice::ReadOnly | mode));
+ bool isSequential = file.isSequential();
+ if (!isSequential) {
+ QVERIFY(file.seek(245));
+ QVERIFY(file.atEnd());
+ }
+
+ char buf[10];
+ int ret = file.readLine(buf, sizeof buf);
+ QCOMPARE(ret, -1);
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+
+ // Do it again to ensure that we get the same result
+ ret = file.readLine(buf, sizeof buf);
+ QCOMPARE(ret, -1);
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+ }
+
+ {
+ QFile file(filename);
+ QVERIFY(file.open(QIODevice::ReadOnly | mode));
+ bool isSequential = file.isSequential();
+ if (!isSequential) {
+ QVERIFY(file.seek(245));
+ QVERIFY(file.atEnd());
+ }
+
+ QByteArray ret = file.readLine();
+ QVERIFY(ret.isNull());
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+
+ // Do it again to ensure that we get the same result
+ ret = file.readLine();
+ QVERIFY(ret.isNull());
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+ }
+
+ {
+ QFile file(filename);
+ QVERIFY(file.open(QIODevice::ReadOnly | mode));
+ bool isSequential = file.isSequential();
+ if (!isSequential) {
+ QVERIFY(file.seek(245));
+ QVERIFY(file.atEnd());
+ }
+
+ char c;
+ QVERIFY(!file.getChar(&c));
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+
+ // Do it again to ensure that we get the same result
+ QVERIFY(!file.getChar(&c));
+ QVERIFY(file.error() == QFile::NoError);
+ QVERIFY(file.atEnd());
+ }
+}
+
+void tst_QFile::task167217()
+{
+ // Regression introduced in 4.3.0; after a failed stat, pos() could no
+ // longer be calculated correctly.
+ QFile::remove("tmp.txt");
+ QFile file("tmp.txt");
+ QVERIFY(!file.exists());
+ QVERIFY(file.open(QIODevice::Append));
+ QVERIFY(file.exists());
+ file.write("qt430", 5);
+ QVERIFY(!file.isSequential());
+ QCOMPARE(file.pos(), qint64(5));
+ file.remove();
+}
+
+#define FILESIZE 65536 * 3
+
+void tst_QFile::map_data()
+{
+ QTest::addColumn<int>("fileSize");
+ QTest::addColumn<int>("offset");
+ QTest::addColumn<int>("size");
+ QTest::addColumn<QFile::FileError>("error");
+
+ QTest::newRow("zero") << FILESIZE << 0 << FILESIZE << QFile::NoError;
+ QTest::newRow("small, but 0") << FILESIZE << 30 << FILESIZE - 30 << QFile::NoError;
+ QTest::newRow("a page") << FILESIZE << 4096 << FILESIZE - 4096 << QFile::NoError;
+ QTest::newRow("+page") << FILESIZE << 5000 << FILESIZE - 5000 << QFile::NoError;
+ QTest::newRow("++page") << FILESIZE << 65576 << FILESIZE - 65576 << QFile::NoError;
+ QTest::newRow("bad size") << FILESIZE << 0 << -1 << QFile::ResourceError;
+ QTest::newRow("bad offset") << FILESIZE << -1 << 1 << QFile::UnspecifiedError;
+ QTest::newRow("zerozero") << FILESIZE << 0 << 0 << QFile::UnspecifiedError;
+}
+
+void tst_QFile::map()
+{
+ QFETCH(int, fileSize);
+ QFETCH(int, offset);
+ QFETCH(int, size);
+ QFETCH(QFile::FileError, error);
+
+ QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile";
+
+#ifdef Q_WS_WINCE
+ fileName = QFileInfo(fileName).absoluteFilePath();
+#endif
+
+ if (QFile::exists(fileName)) {
+ QVERIFY(QFile::setPermissions(fileName,
+ QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser));
+ QFile::remove(fileName);
+ }
+ QFile file(fileName);
+
+ // invalid, not open
+ uchar *memory = file.map(0, size);
+ QVERIFY(!memory);
+ QCOMPARE(file.error(), QFile::PermissionsError);
+ QVERIFY(!file.unmap(memory));
+ QCOMPARE(file.error(), QFile::PermissionsError);
+
+ // make a file
+ QVERIFY(file.open(QFile::ReadWrite));
+ QVERIFY(file.resize(fileSize));
+ QVERIFY(file.flush());
+ file.close();
+ QVERIFY(file.open(QFile::ReadWrite));
+ memory = file.map(offset, size);
+ if (error != QFile::NoError) {
+
+ QVERIFY(file.error() != QFile::NoError);
+ return;
+ }
+
+ QCOMPARE(file.error(), error);
+ QVERIFY(memory);
+ memory[0] = 'Q';
+ QVERIFY(file.unmap(memory));
+ QCOMPARE(file.error(), QFile::NoError);
+
+ // Verify changes were saved
+ memory = file.map(offset, size);
+ QCOMPARE(file.error(), QFile::NoError);
+ QVERIFY(memory);
+ QVERIFY(memory[0] == 'Q');
+ QVERIFY(file.unmap(memory));
+ QCOMPARE(file.error(), QFile::NoError);
+
+ // hpux wont let you map multiple times.
+#if !defined(Q_OS_HPUX) && !defined(Q_USE_DEPRECATED_MAP_API) && !defined(Q_OS_WINCE)
+ // exotic test to make sure that multiple maps work
+
+ // note: windows ce does not reference count mutliple maps
+ // it's essentially just the same reference but it
+ // cause a resource lock on the file which prevents it
+ // from being removed uchar *memory1 = file.map(0, file.size());
+ uchar *memory1 = file.map(0, file.size());
+ QCOMPARE(file.error(), QFile::NoError);
+ uchar *memory2 = file.map(0, file.size());
+ QCOMPARE(file.error(), QFile::NoError);
+ QVERIFY(memory1);
+ QVERIFY(memory2);
+ QVERIFY(file.unmap(memory1));
+ QCOMPARE(file.error(), QFile::NoError);
+ QVERIFY(file.unmap(memory2));
+ QCOMPARE(file.error(), QFile::NoError);
+ memory1 = file.map(0, file.size());
+ QCOMPARE(file.error(), QFile::NoError);
+ QVERIFY(memory1);
+ QVERIFY(file.unmap(memory1));
+ QCOMPARE(file.error(), QFile::NoError);
+#endif
+
+ file.close();
+
+#if defined(Q_OS_SYMBIAN)
+ if (false) // No permissions for user makes no sense in Symbian
+#elif defined(Q_OS_UNIX)
+ if (::getuid() != 0)
+ // root always has permissions
+#endif
+ {
+ // Change permissions on a file, just to confirm it would fail
+ QFile::Permissions originalPermissions = file.permissions();
+ QVERIFY(file.setPermissions(QFile::ReadOther));
+ QVERIFY(!file.open(QFile::ReadWrite));
+ memory = file.map(offset, size);
+ QCOMPARE(file.error(), QFile::PermissionsError);
+ QVERIFY(!memory);
+ QVERIFY(file.setPermissions(originalPermissions));
+ }
+ QVERIFY(file.remove());
+}
+
+void tst_QFile::mapResource_data()
+{
+ QTest::addColumn<int>("offset");
+ QTest::addColumn<int>("size");
+ QTest::addColumn<QFile::FileError>("error");
+ QTest::addColumn<QString>("fileName");
+
+ QString validFile = ":/tst_qfileinfo/resources/file1.ext1";
+ QString invalidFile = ":/tst_qfileinfo/resources/filefoo.ext1";
+
+ for (int i = 0; i < 2; ++i) {
+ QString file = (i == 0) ? validFile : invalidFile;
+ QTest::newRow("0, 0") << 0 << 0 << QFile::UnspecifiedError << file;
+ QTest::newRow("0, BIG") << 0 << 4096 << QFile::UnspecifiedError << file;
+ QTest::newRow("-1, 0") << -1 << 0 << QFile::UnspecifiedError << file;
+ QTest::newRow("0, -1") << 0 << -1 << QFile::UnspecifiedError << file;
+ }
+
+ QTest::newRow("0, 1") << 0 << 1 << QFile::NoError << validFile;
+}
+
+void tst_QFile::mapResource()
+{
+ QFETCH(QString, fileName);
+ QFETCH(int, offset);
+ QFETCH(int, size);
+ QFETCH(QFile::FileError, error);
+
+ QFile file(fileName);
+ uchar *memory = file.map(offset, size);
+ QCOMPARE(file.error(), error);
+ QVERIFY((error == QFile::NoError) ? (memory != 0) : (memory == 0));
+ if (error == QFile::NoError)
+ QCOMPARE(QString(memory[0]), QString::number(offset + 1));
+ QVERIFY(file.unmap(memory));
+}
+
+void tst_QFile::mapOpenMode_data()
+{
+ QTest::addColumn<int>("openMode");
+
+ QTest::newRow("ReadOnly") << int(QIODevice::ReadOnly);
+ //QTest::newRow("WriteOnly") << int(QIODevice::WriteOnly); // this doesn't make sense
+ QTest::newRow("ReadWrite") << int(QIODevice::ReadWrite);
+ QTest::newRow("ReadOnly,Unbuffered") << int(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ QTest::newRow("ReadWrite,Unbuffered") << int(QIODevice::ReadWrite | QIODevice::Unbuffered);
+}
+
+void tst_QFile::mapOpenMode()
+{
+ QFETCH(int, openMode);
+ static const qint64 fileSize = 4096;
+
+ QByteArray pattern(fileSize, 'A');
+
+ QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile";
+ if (QFile::exists(fileName)) {
+ QVERIFY(QFile::setPermissions(fileName,
+ QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser));
+ QFile::remove(fileName);
+ }
+ QFile file(fileName);
+
+ // make a file
+ QVERIFY(file.open(QFile::ReadWrite));
+ QVERIFY(file.write(pattern));
+ QVERIFY(file.flush());
+ file.close();
+
+ // open according to our mode
+ QVERIFY(file.open(QIODevice::OpenMode(openMode)));
+
+ uchar *memory = file.map(0, fileSize);
+ QVERIFY(memory);
+ QVERIFY(memcmp(memory, pattern, fileSize) == 0);
+
+ if (openMode & QIODevice::WriteOnly) {
+ // try to write to the file
+ *memory = 'a';
+ file.unmap(memory);
+ file.close();
+ file.open(QIODevice::OpenMode(openMode));
+ file.seek(0);
+ char c;
+ QVERIFY(file.getChar(&c));
+ QCOMPARE(c, 'a');
+ }
+
+ file.close();
+}
+
+void tst_QFile::openDirectory()
+{
+ QFile f1(SRCDIR "resources");
+ // it's a directory, it must exist
+ QVERIFY(f1.exists());
+
+ // ...but not be openable
+ QVERIFY(!f1.open(QIODevice::ReadOnly));
+ f1.close();
+ QVERIFY(!f1.open(QIODevice::ReadOnly|QIODevice::Unbuffered));
+ f1.close();
+ QVERIFY(!f1.open(QIODevice::ReadWrite));
+ f1.close();
+ QVERIFY(!f1.open(QIODevice::WriteOnly));
+ f1.close();
+ QVERIFY(!f1.open(QIODevice::WriteOnly|QIODevice::Unbuffered));
+ f1.close();
+}
+
+void tst_QFile::openStandardStreamsFileDescriptors()
+{
+#ifdef Q_WS_WINCE
+ //allthough Windows CE (not mobile!) has functions that allow redirecting
+ //the standard file descriptors to a file (see SetStdioPathW/GetStdioPathW)
+ //it does not have functions to simply open them like below .
+ QSKIP("Opening standard streams on Windows CE via descriptor not implemented", SkipAll);
+#endif
+ // Using file descriptors
+ {
+ QFile in;
+ in.open(STDIN_FILENO, QIODevice::ReadOnly);
+ QCOMPARE( in.pos(), (qint64)0 );
+ QCOMPARE( in.size(), (qint64)0 );
+ QVERIFY( in.isSequential() );
+ }
+
+ {
+ QFile out;
+ out.open(STDOUT_FILENO, QIODevice::WriteOnly);
+ QCOMPARE( out.pos(), (qint64)0 );
+ QCOMPARE( out.size(), (qint64)0 );
+ QVERIFY( out.isSequential() );
+ }
+
+ {
+ QFile err;
+ err.open(STDERR_FILENO, QIODevice::WriteOnly);
+ QCOMPARE( err.pos(), (qint64)0 );
+ QCOMPARE( err.size(), (qint64)0 );
+ QVERIFY( err.isSequential() );
+ }
+}
+
+void tst_QFile::openStandardStreamsBufferedStreams()
+{
+#if defined (Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ QSKIP("Unix only test.", SkipAll);
+#endif
+ // Using streams
+ {
+ QFile in;
+ in.open(stdin, QIODevice::ReadOnly);
+ QCOMPARE( in.pos(), (qint64)0 );
+ QCOMPARE( in.size(), (qint64)0 );
+ QVERIFY( in.isSequential() );
+ }
+
+ {
+ QFile out;
+ out.open(stdout, QIODevice::WriteOnly);
+ QCOMPARE( out.pos(), (qint64)0 );
+ QCOMPARE( out.size(), (qint64)0 );
+ QVERIFY( out.isSequential() );
+ }
+
+ {
+ QFile err;
+ err.open(stderr, QIODevice::WriteOnly);
+ QCOMPARE( err.pos(), (qint64)0 );
+ QCOMPARE( err.size(), (qint64)0 );
+ QVERIFY( err.isSequential() );
+ }
+}
+
+void tst_QFile::openStandardStreams()
+{
+ openStandardStreamsFileDescriptors();
+ openStandardStreamsBufferedStreams();
+}
+
+void tst_QFile::writeNothing()
+{
+ for (int i = 0; i < NumberOfFileTypes; ++i) {
+ QFile file("file.txt");
+ QVERIFY( openFile(file, QIODevice::WriteOnly | QIODevice::Unbuffered, FileType(i)) );
+ QVERIFY( 0 == file.write((char *)0, 0) );
+ QCOMPARE( file.error(), QFile::NoError );
+ closeFile(file);
+ }
+}
+
+void tst_QFile::resize_data()
+{
+ QTest::addColumn<int>("filetype");
+
+ QTest::newRow("native") << int(OpenQFile);
+ QTest::newRow("fileno") << int(OpenFd);
+ QTest::newRow("stream") << int(OpenStream);
+#ifdef Q_OS_SYMBIAN
+ QTest::newRow("rfile") << int(OpenRFile);
+#endif
+}
+
+void tst_QFile::resize()
+{
+ QFETCH(int, filetype);
+ QString filename(QLatin1String("file.txt"));
+ QFile file(filename);
+ QVERIFY(openFile(file, QIODevice::ReadWrite, FileType(filetype)));
+ QVERIFY(file.resize(8));
+ QCOMPARE(file.size(), qint64(8));
+ closeFile(file);
+ QFile::resize(filename, 4);
+ QCOMPARE(QFileInfo(filename).size(), qint64(4));
+ QVERIFY(QFile::remove(filename));
+}
+
+void tst_QFile::objectConstructors()
+{
+ QObject ob;
+ QFile* file1 = new QFile(SRCDIR "testfile.txt", &ob);
+ QFile* file2 = new QFile(&ob);
+ QVERIFY(file1->exists());
+ QVERIFY(!file2->exists());
+}
+
+#ifdef Q_OS_SYMBIAN
+void tst_QFile::platformSecurity_data()
+{
+ QTest::addColumn<QString>("file");
+ QTest::addColumn<bool>("readable");
+ QTest::addColumn<bool>("writable");
+
+ QString selfname = QCoreApplication::applicationFilePath();
+ QString ownprivate = QCoreApplication::applicationDirPath();
+ QString owndrive = selfname.left(2);
+ bool amiprivileged = RProcess().HasCapability(ECapabilityAllFiles);
+ QTest::newRow("resource") << owndrive + "/resource/apps/tst_qfile.rsc" << true << amiprivileged;
+ QTest::newRow("sys") << selfname << amiprivileged << false;
+ QTest::newRow("own private") << ownprivate + "/testfile.txt" << true << true;
+ QTest::newRow("other private") << owndrive + "/private/10003a3f/import/apps/tst_qfile_reg.rsc" << amiprivileged << amiprivileged;
+}
+
+void tst_QFile::platformSecurity()
+{
+ QFETCH(QString,file);
+ QFETCH(bool,readable);
+ QFETCH(bool,writable);
+
+ {
+ QFile f(file);
+ QCOMPARE(f.open(QIODevice::ReadOnly), readable);
+ }
+
+ {
+ QFile f(file);
+ QCOMPARE(f.open(QIODevice::ReadOnly | QIODevice::Unbuffered), readable);
+ }
+
+ //append mode used to avoid truncating the files.
+ {
+ QFile f(file);
+ QCOMPARE(f.open(QIODevice::WriteOnly | QIODevice::Append), writable);
+ }
+
+ {
+ QFile f(file);
+ QCOMPARE(f.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered), writable);
+ }
+
+ {
+ QFile f(file);
+ QCOMPARE(f.open(QIODevice::ReadWrite), writable);
+ }
+
+ {
+ QFile f(file);
+ QCOMPARE(f.open(QIODevice::ReadWrite | QIODevice::Unbuffered), writable);
+ }
+}
+#endif
+
+void tst_QFile::caseSensitivity()
+{
+#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WIN) || defined(Q_OS_MAC)
+ const bool caseSensitive = false;
+#else
+ const bool caseSensitive = true;
+#endif
+ QByteArray testData("a little test");
+ QString filename("File.txt");
+ {
+ QFile f(filename);
+ QVERIFY(f.open(QIODevice::WriteOnly));
+ QVERIFY(f.write(testData));
+ f.close();
+ }
+ QStringList alternates;
+ QFileInfo fi(filename);
+ QVERIFY(fi.exists());
+ alternates << "file.txt" << "File.TXT" << "fIlE.TxT" << fi.absoluteFilePath().toUpper() << fi.absoluteFilePath().toLower();
+ foreach (QString alt, alternates) {
+ QFileInfo fi2(alt);
+ QCOMPARE(fi2.exists(), !caseSensitive);
+ QCOMPARE(fi.size() == fi2.size(), !caseSensitive);
+ QFile f2(alt);
+ QCOMPARE(f2.open(QIODevice::ReadOnly), !caseSensitive);
+ if (!caseSensitive)
+ QCOMPARE(f2.readAll(), testData);
+ }
+}
+
+//MSVCRT asserts when any function is called with a closed file handle.
+//This replaces the default crashing error handler with one that ignores the error (allowing EBADF to be returned)
+class AutoIgnoreInvalidParameter
+{
+public:
+#if defined(Q_OS_WIN) && defined (Q_CC_MSVC)
+ static void ignore_invalid_parameter(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t) {}
+ AutoIgnoreInvalidParameter()
+ {
+ oldHandler = _set_invalid_parameter_handler(ignore_invalid_parameter);
+ //also disable the abort/retry/ignore popup
+ oldReportMode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+ }
+ ~AutoIgnoreInvalidParameter()
+ {
+ //restore previous settings
+ _set_invalid_parameter_handler(oldHandler);
+ _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
+ }
+ _invalid_parameter_handler oldHandler;
+ int oldReportMode;
+#endif
+};
+
+void tst_QFile::autocloseHandle()
+{
+#ifdef Q_OS_SYMBIAN
+ // these tests are a bit different, because using a closed file handle results in a panic rather than error
+ {
+ QFile file("readonlyfile");
+ QFile file2("readonlyfile");
+ QVERIFY(openFile(file, QIODevice::ReadOnly, OpenRFile, QFile::AutoCloseHandle));
+ // file is opened with mandatory lock, so opening again should fail
+ QVERIFY(!file2.open(QIODevice::ReadOnly));
+
+ file.close();
+ // opening again should now succeed (because handle is closed)
+ QVERIFY(file2.open(QIODevice::ReadOnly));
+ }
+
+ {
+ QFile file("readonlyfile");
+ QFile file2("readonlyfile");
+ QVERIFY(openFile(file, QIODevice::ReadOnly, OpenRFile, QFile::DontCloseHandle));
+ // file is opened with mandatory lock, so opening again should fail
+ QVERIFY(!file2.open(QIODevice::ReadOnly));
+
+ file.close();
+ // opening again should still fail (because handle is not auto closed)
+ QVERIFY(!file2.open(QIODevice::ReadOnly));
+
+ rfile_.Close();
+ // now it should succeed
+ QVERIFY(file2.open(QIODevice::ReadOnly));
+ }
+#endif
+
+ {
+ QFile file("readonlyfile");
+ QVERIFY(openFile(file, QIODevice::ReadOnly, OpenFd, QFile::AutoCloseHandle));
+ int fd = fd_;
+ QCOMPARE(file.handle(), fd);
+ file.close();
+ fd_ = -1;
+ QCOMPARE(file.handle(), -1);
+ AutoIgnoreInvalidParameter a;
+ Q_UNUSED(a);
+ //file is closed, read should fail
+ char buf;
+ QCOMPARE((int)QT_READ(fd, &buf, 1), -1);
+ QVERIFY(errno = EBADF);
+ }
+
+ {
+ QFile file("readonlyfile");
+ QVERIFY(openFile(file, QIODevice::ReadOnly, OpenFd, QFile::DontCloseHandle));
+ QCOMPARE(file.handle(), fd_);
+ file.close();
+ QCOMPARE(file.handle(), -1);
+ //file is not closed, read should succeed
+ char buf;
+ QCOMPARE((int)QT_READ(fd_, &buf, 1), 1);
+ ::close(fd_);
+ fd_ = -1;
+ }
+
+ {
+ QFile file("readonlyfile");
+ QVERIFY(openFile(file, QIODevice::ReadOnly, OpenStream, QFile::AutoCloseHandle));
+ int fd = fileno(stream_);
+ QCOMPARE(file.handle(), fd);
+ file.close();
+ stream_ = 0;
+ QCOMPARE(file.handle(), -1);
+ AutoIgnoreInvalidParameter a;
+ Q_UNUSED(a);
+ //file is closed, read should fail
+ char buf;
+ QCOMPARE((int)QT_READ(fd, &buf, 1), -1); //not using fread because the FILE* was freed by fclose
+ }
+
+ {
+ QFile file("readonlyfile");
+ QVERIFY(openFile(file, QIODevice::ReadOnly, OpenStream, QFile::DontCloseHandle));
+ QCOMPARE(file.handle(), fileno(stream_));
+ file.close();
+ QCOMPARE(file.handle(), -1);
+ //file is not closed, read should succeed
+ char buf;
+ QCOMPARE(int(::fread(&buf, 1, 1, stream_)), 1);
+ ::fclose(stream_);
+ stream_ = 0;
+ }
+}
+
+QTEST_MAIN(tst_QFile)
+#include "tst_qfile.moc"
diff --git a/tests/auto/corelib/io/qfile/two.dots.file b/tests/auto/corelib/io/qfile/two.dots.file
new file mode 100644
index 0000000000..1910281566
--- /dev/null
+++ b/tests/auto/corelib/io/qfile/two.dots.file
@@ -0,0 +1 @@
+foo \ No newline at end of file