qt5base-lts/tests/auto/qfile/tst_qfile.cpp
Qt by Nokia 38be0d1383 Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:

http://qt.gitorious.org/qt/pages/GitIntroductionWithQt

If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.

Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
2011-04-27 12:05:43 +02:00

3405 lines
97 KiB
C++

/****************************************************************************
**
** 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$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $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
}
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 -> Makefile") << QString("renamefile") << QString("Makefile") << 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"