/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN QT_BEGIN_NAMESPACE extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; QT_END_NAMESPACE #endif #if !defined(Q_OS_WINCE) #include #endif #include #ifdef Q_OS_WIN # include #else # include # include #endif #ifdef Q_OS_MAC # include #elif defined(Q_OS_LINUX) # include #elif defined(Q_OS_FREEBSD) # include # include #elif defined(Q_OS_IRIX) # include #elif defined(Q_OS_WINCE) # include #endif #include #include #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) #include "../../../network-settings.h" #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) class tst_QFile : public QObject { Q_OBJECT private slots: void init(); void cleanup(); 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 permissionsNtfs_data(); void permissionsNtfs(); 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 openStandardStreamsFileDescriptors(); void openStandardStreamsBufferedStreams(); void resize_data(); void resize(); void objectConstructors(); void caseSensitivity(); void autocloseHandle(); void posAfterFailedStat(); void openDirectory(); void writeNothing(); public: // disabled this test for the moment... it hangs void invalidFile_data(); void invalidFile(); private: enum FileType { OpenQFile, OpenFd, OpenStream, NumberOfFileTypes }; 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); } 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); case NumberOfFileTypes: break; } return false; } void closeFile(QFile &file) { file.close(); if (-1 != fd_) QT_CLOSE(fd_); if (stream_) ::fclose(stream_); fd_ = -1; stream_ = 0; } int fd_; FILE *stream_; }; void tst_QFile::init() { fd_ = -1; stream_ = 0; } void tst_QFile::cleanup() { // 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() { QString workingDir = QFileInfo(QFINDTESTDATA("stdinprocess")).absolutePath(); QVERIFY2(!workingDir.isEmpty(), qPrintable("Could not find working directory!")); QVERIFY2(QDir::setCurrent(workingDir), qPrintable("Could not chdir to " + workingDir)); 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( QFINDTESTDATA("testfile.txt") ); QVERIFY(f.exists()); 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("filename"); QTest::addColumn("mode"); QTest::addColumn("ok"); QTest::addColumn("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(QFINDTESTDATA("testfile.txt")) << int(QIODevice::ReadOnly) << true << QFile::NoError; QTest::newRow( "exist_writeOnly" ) << QString("readonlyfile") << int(QIODevice::WriteOnly) << false << QFile::OpenError; QTest::newRow( "exist_append" ) << QString("readonlyfile") << int(QIODevice::Append) << false << QFile::OpenError; QTest::newRow( "nonexist_readOnly" ) << QString("nonExist.txt") << int(QIODevice::ReadOnly) << false << QFile::OpenError; QTest::newRow("emptyfile") << QString("") << int(QIODevice::ReadOnly) << false << QFile::OpenError; QTest::newRow("nullfile") << QString() << int(QIODevice::ReadOnly) << false << QFile::OpenError; QTest::newRow("two-dots") << QString(QFINDTESTDATA("two.dots.file")) << int(QIODevice::ReadOnly) << true << QFile::NoError; QTest::newRow("readonlyfile") << QString("readonlyfile") << int(QIODevice::WriteOnly) << false << QFile::OpenError; QTest::newRow("noreadfile") << QString("noreadfile") << int(QIODevice::ReadOnly) << false << QFile::OpenError; #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) //opening devices requires administrative privileges (and elevation). HANDLE hTest = CreateFile(_T("\\\\.\\PhysicalDrive0"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hTest != INVALID_HANDLE_VALUE) { CloseHandle(hTest); QTest::newRow("//./PhysicalDrive0") << QString("//./PhysicalDrive0") << int(QIODevice::ReadOnly) << true << QFile::NoError; } else { QTest::newRow("//./PhysicalDrive0") << QString("//./PhysicalDrive0") << int(QIODevice::ReadOnly) << false << QFile::OpenError; } 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_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"); #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(QFINDTESTDATA("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("filename"); QTest::addColumn("size"); QTest::newRow( "exist01" ) << QString(QFINDTESTDATA("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_OS_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); } // Currently low level file I/O is not well supported on Windows CE, so // skip this part of the test. #ifndef Q_OS_WINCE { 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); } #endif } 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() { 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( QFINDTESTDATA("testfile.txt") ); QVERIFY(f.open( QIODevice::ReadOnly )); int size = f.size(); f.seek( size ); bool end = f.atEnd(); f.close(); QVERIFY(end); } void tst_QFile::readLine() { QFile f( QFINDTESTDATA("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( QFINDTESTDATA("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("textMode"); QTest::addColumn("fileName"); QTest::newRow( "TextMode unixfile" ) << true << QFINDTESTDATA("testfile.txt"); QTest::newRow( "BinaryMode unixfile" ) << false << QFINDTESTDATA("testfile.txt"); QTest::newRow( "TextMode dosfile" ) << true << QFINDTESTDATA("dosfile.txt"); QTest::newRow( "BinaryMode dosfile" ) << false << QFINDTESTDATA("dosfile.txt"); QTest::newRow( "TextMode bigfile" ) << true << QFINDTESTDATA("tst_qfile.cpp"); QTest::newRow( "BinaryMode bigfile" ) << false << QFINDTESTDATA("tst_qfile.cpp"); QVERIFY(QFile(QFINDTESTDATA("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) QSKIP("Currently no stdin/out supported for Windows CE"); #endif #if defined(QT_NO_PROCESS) QSKIP("Qt was compiled with QT_NO_PROCESS"); #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) QSKIP("Currently no stdin/out supported for Windows CE"); #endif #if defined(QT_NO_PROCESS) QSKIP("Qt was compiled with QT_NO_PROCESS"); #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) QSKIP("Currently no stdin/out supported for Windows CE"); #endif #if defined(QT_NO_PROCESS) QSKIP("Qt was compiled with QT_NO_PROCESS"); #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(QFINDTESTDATA("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(QFINDTESTDATA("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( QFINDTESTDATA("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( QFINDTESTDATA("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(QFINDTESTDATA("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("fileName"); #if !defined(Q_OS_WIN) 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( "failinvalid" ); 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("file"); QTest::addColumn("perms"); QTest::addColumn("expected"); QTest::addColumn("create"); QTest::newRow("data0") << QCoreApplication::instance()->applicationFilePath() << uint(QFile::ExeUser) << true << false; QTest::newRow("data1") << QFINDTESTDATA("tst_qfile.cpp") << uint(QFile::ReadUser) << true << false; QTest::newRow("readonly") << QFINDTESTDATA("readonlyfile") << uint(QFile::WriteUser) << false << false; #ifndef Q_OS_WINCE QTest::newRow("longfile") << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName" "longFileNamelongFileNamelongFileNamelongFileName" "longFileNamelongFileNamelongFileNamelongFileName" "longFileNamelongFileNamelongFileNamelongFileName" "longFileNamelongFileNamelongFileNamelongFileName.txt") << uint(QFile::ReadUser) << true << true; #endif QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ReadUser) << true << false; QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::WriteUser) << false << false; QTest::newRow("resource3") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ExeUser) << false << false; } void tst_QFile::permissions() { QFETCH(QString, file); QFETCH(uint, perms); QFETCH(bool, expected); QFETCH(bool, create); if (create) { QFile fc(file); QVERIFY(fc.open(QFile::WriteOnly)); QVERIFY(fc.write("hello\n")); fc.close(); } QFile f(file); QFile::Permissions memberResult = f.permissions() & perms; QFile::Permissions staticResult = QFile::permissions(file) & perms; if (create) { QFile::remove(file); } #ifdef Q_OS_WIN if (qt_ntfs_permission_lookup) QEXPECT_FAIL("readonly", "QTBUG-25630", Abort); #endif QCOMPARE((memberResult == QFile::Permissions(perms)), expected); QCOMPARE((staticResult == QFile::Permissions(perms)), expected); } void tst_QFile::permissionsNtfs_data() { permissions_data(); } void tst_QFile::permissionsNtfs() { #ifdef Q_OS_WIN QScopedValueRollback ntfsMode(qt_ntfs_permission_lookup); qt_ntfs_permission_lookup++; permissions(); #else QSKIP("windows test"); #endif } void tst_QFile::setPermissions() { 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(QFINDTESTDATA("tst_qfile.cpp"), "tst_qfile_copy.cpp")); QFile in1(QFINDTESTDATA("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(QFINDTESTDATA("forCopying.txt"), newName)); QVERIFY(!QFile::exists(QFINDTESTDATA("qt_temp.XXXXXX"))); QVERIFY(QFile::remove(newName)); } void tst_QFile::copyShouldntOverwrite() { // Copy should not overwrite existing files. QFile::remove("tst_qfile.cpy"); QFile file(QFINDTESTDATA("tst_qfile.cpp")); QVERIFY(file.copy("tst_qfile.cpy")); bool ok = QFile::setPermissions("tst_qfile.cpy", QFile::WriteOther); 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_OS_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 #include #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() { QFile::remove("myLink.lnk"); QFileInfo info1(QFINDTESTDATA("tst_qfile.cpp")); QString referenceTarget = QDir::cleanPath(info1.absoluteFilePath()); QVERIFY(QFile::link(QFINDTESTDATA("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() { 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() { 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", 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() { QFile::remove("myLink2.lnk"); QFileInfo info1("file12"); QVERIFY(QFile::link("file12", "myLink2.lnk")); QFileInfo info2("myLink2.lnk"); QVERIFY(info2.isSymLink()); QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath()); QVERIFY(QFile::remove(info2.absoluteFilePath())); QVERIFY(QFile::link("ole/..", "myLink2.lnk")); QCOMPARE(QFileInfo("myLink2.lnk").symLinkTarget(), QDir::currentPath()); } void tst_QFile::readTextFile_data() { QTest::addColumn("in"); QTest::addColumn("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(QFINDTESTDATA("testlog.txt")); QVERIFY(file.open(QIODevice::ReadOnly)); file.read(4097); } { QFile file(QFINDTESTDATA("testlog.txt")); QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); file.read(4097); } } void tst_QFile::writeTextFile_data() { QTest::addColumn("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. 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."); 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 readSignalSpy(&tailFile, SIGNAL(readyRead())); QVERIFY(readSignalSpy.isValid()); file.write("", 1); QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); QCOMPARE(readSignalSpy.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").toLatin1() , "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() { #ifndef Q_OS_UNIX QSKIP("Unix only test."); #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 #define BUFFSIZE 1 #define FILESIZE 0x10000000f void tst_QFile::largeFileSupport() { #ifdef Q_OS_SOLARIS QSKIP("Solaris does not support statfs"); #else qlonglong sizeNeeded = 2147483647; sizeNeeded *= 2; sizeNeeded += 1024; qlonglong freespace = qlonglong(0); #ifdef Q_OS_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(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("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("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) 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)); } #ifdef QT_BUILD_INTERNAL class MyEngine : public QAbstractFileEngine { public: MyEngine(int n) { number = n; } virtual ~MyEngine() {} void setFileName(const QString &) {} bool open(QIODevice::OpenMode) { 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); } }; #endif 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)); #ifdef QT_BUILD_INTERNAL // 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)); #endif } #ifdef QT_BUILD_INTERNAL class MyRecursiveHandler : public QAbstractFileEngineHandler { public: inline QAbstractFileEngine *create(const QString &fileName) const { if (fileName.startsWith(":!")) { QDir dir; QString realFile = QFINDTESTDATA(fileName.mid(2)); if (dir.exists(realFile)) return new QFSFileEngine(realFile); } return 0; } }; #endif void tst_QFile::useQFileInAFileHandler() { #ifdef QT_BUILD_INTERNAL // This test should not dead-lock MyRecursiveHandler handler; QFile file(":!tst_qfile.cpp"); QVERIFY(file.exists()); #else QSKIP("This test requires -developer-build."); #endif } 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"); 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("fileName"); QTest::addColumn("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; #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) int resizeSize = 1024 * 1024; // WinCE does 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"); #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").toLatin1() , "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("source"); QTest::addColumn("destination"); QTest::addColumn("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) 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); #if defined(Q_OS_UNIX) if (strcmp(QTest::currentDataTag(), "renamefile -> /etc/renamefile") == 0) { if (::getuid() == 0) QSKIP("Running this test as root doesn't make sense"); } #endif 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. */ 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(QFINDTESTDATA("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) QFile file(QFINDTESTDATA("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(qPrintable(QFINDTESTDATA("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(qPrintable(QFINDTESTDATA("tst_qfile.cpp")), QT_OPEN_RDONLY); file3.open(fd, QIODevice::ReadOnly); QCOMPARE(int(file3.handle()), fd); QT_CLOSE(fd); #endif } void tst_QFile::nativeHandleLeaks() { 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 } void tst_QFile::readEof_data() { QTest::addColumn("filename"); QTest::addColumn("imode"); QTest::newRow("buffered") << QFINDTESTDATA("testfile.txt") << 0; QTest::newRow("unbuffered") << QFINDTESTDATA("testfile.txt") << int(QIODevice::Unbuffered); #if defined(Q_OS_UNIX) 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::posAfterFailedStat() { // Regression test for a bug 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("fileSize"); QTest::addColumn("offset"); QTest::addColumn("size"); QTest::addColumn("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_OS_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_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("offset"); QTest::addColumn("size"); QTest::addColumn("error"); QTest::addColumn("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("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(QFINDTESTDATA("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(); } static qint64 streamExpectedSize(int fd) { QT_STATBUF sb; if (QT_FSTAT(fd, &sb) != -1) return sb.st_size; return 0; } static qint64 streamCurrentPosition(int fd) { QT_OFF_T pos = QT_LSEEK(fd, 0, SEEK_CUR); if (pos != -1) return pos; return 0; } static qint64 streamCurrentPosition(FILE *f) { QT_OFF_T pos = QT_FTELL(f); if (pos != -1) return pos; return 0; } void tst_QFile::openStandardStreamsFileDescriptors() { #ifdef Q_OS_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"); #endif { QFile in; in.open(STDIN_FILENO, QIODevice::ReadOnly); QCOMPARE( in.pos(), streamCurrentPosition(STDIN_FILENO) ); QCOMPARE( in.size(), streamExpectedSize(STDIN_FILENO) ); } { QFile out; QVERIFY(out.open(STDOUT_FILENO, QIODevice::WriteOnly)); QCOMPARE( out.pos(), streamCurrentPosition(STDOUT_FILENO) ); QCOMPARE( out.size(), streamExpectedSize(STDOUT_FILENO) ); } { QFile err; err.open(STDERR_FILENO, QIODevice::WriteOnly); QCOMPARE( err.pos(), streamCurrentPosition(STDERR_FILENO) ); QCOMPARE( err.size(), streamExpectedSize(STDERR_FILENO) ); } } void tst_QFile::openStandardStreamsBufferedStreams() { #ifdef Q_OS_WINCE QSKIP("Not tested on Windows CE."); #endif // Using streams { QFile in; in.open(stdin, QIODevice::ReadOnly); QCOMPARE( in.pos(), streamCurrentPosition(stdin) ); QCOMPARE( in.size(), streamExpectedSize(QT_FILENO(stdin)) ); } { QFile out; out.open(stdout, QIODevice::WriteOnly); QCOMPARE( out.pos(), streamCurrentPosition(stdout) ); QCOMPARE( out.size(), streamExpectedSize(QT_FILENO(stdout)) ); } { QFile err; err.open(stderr, QIODevice::WriteOnly); QCOMPARE( err.pos(), streamCurrentPosition(stderr) ); QCOMPARE( err.size(), streamExpectedSize(QT_FILENO(stderr)) ); } } 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("filetype"); QTest::newRow("native") << int(OpenQFile); QTest::newRow("fileno") << int(OpenFd); QTest::newRow("stream") << int(OpenStream); } 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(QFINDTESTDATA("testfile.txt"), &ob); QFile* file2 = new QFile(&ob); QVERIFY(file1->exists()); QVERIFY(!file2->exists()); } void tst_QFile::caseSensitivity() { #if 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() { { 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"