tests/auto/qfile/tst_qfile.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
--- a/tests/auto/qfile/tst_qfile.cpp	Tue Jan 26 12:42:25 2010 +0200
+++ b/tests/auto/qfile/tst_qfile.cpp	Tue Feb 02 00:43:10 2010 +0200
@@ -79,6 +79,22 @@
 # 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=
@@ -105,6 +121,7 @@
     void openUnbuffered();
     void size_data();
     void size();
+    void sizeNoExist();
     void seek();
     void setSize();
     void setSizeSeek();
@@ -187,15 +204,96 @@
     void mapOpenMode_data();
     void mapOpenMode();
 
+    void openStandardStreams();
+
     // --- 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 };
+
+    void openStandardStreamsFileDescriptors();
+    void openStandardStreamsBufferedStreams();
+
+    bool openFd(QFile &file, QIODevice::OpenMode mode)
+    {
+        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);
+    }
+
+    bool openStream(QFile &file, QIODevice::OpenMode mode)
+    {
+        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);
+    }
+
+    bool openFile(QFile &file, QIODevice::OpenMode mode, FileType type = OpenQFile)
+    {
+        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);
+
+            case OpenStream:
+                return openStream(file, mode);
+        }
+
+        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_;
 };
 
 tst_QFile::tst_QFile()
@@ -211,6 +309,8 @@
 {
 // TODO: Add initialization code here.
 // This will be executed immediately before each test is run.
+    fd_ = -1;
+    stream_ = 0;
 }
 
 void tst_QFile::cleanup()
@@ -239,6 +339,11 @@
     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()
@@ -438,23 +543,66 @@
 void tst_QFile::size_data()
 {
     QTest::addColumn<QString>("filename");
-    QTest::addColumn<int>("size");
-
-    QTest::newRow( "exist01" ) << QString(SRCDIR "testfile.txt") << 245;
-    QTest::newRow( "nonexist01" ) << QString("foo.txt") << 0;
+    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() + "/testsharewritable/test.pri") << 34;
+    QTest::newRow("unc") << "//" + QString(QtNetworkSettings::winServerName() + "/testsharewritable/test.pri") << (qint64)34;
 #endif
 }
 
 void tst_QFile::size()
 {
     QFETCH( QString, filename );
-    QFile f( filename );
-    QTEST( (int)f.size(), "size" );
-    if (f.open(QFile::ReadOnly))
-        QTEST( (int)f.size(), "size" );
+    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()
@@ -467,6 +615,7 @@
     QVERIFY(file.seek(10));
     QCOMPARE(file.pos(), qint64(10));
     QCOMPARE(file.size(), qint64(0));
+    file.close();
     QFile::remove("newfile.txt");
 }
 
@@ -615,6 +764,7 @@
 
     QProcess process;
     process.start("stdinprocess/stdinprocess all");
+    QVERIFY( process.waitForStarted() );
     for (int i = 0; i < 5; ++i) {
         QTest::qWait(1000);
         process.write(lotsOfData);
@@ -991,9 +1141,15 @@
     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::ReadOwner | QFile::WriteOwner));
+            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.
@@ -1002,6 +1158,7 @@
     QVERIFY(QFile::exists("file-copy-destination.txt"));
     QVERIFY(!file.isOpen());
 
+    file.close(); 
     QFile::remove("file-copy-destination.txt");
 }
 
@@ -1909,53 +2066,71 @@
 void tst_QFile::writeLargeDataBlock_data()
 {
     QTest::addColumn<QString>("fileName");
-
-    QTest::newRow("localfile") << QString("./largeblockfile.txt");
+    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;
+
 #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());
+        .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);
-
-    // Generate a 64MB array with well defined contents.
-    QByteArray array;
-#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);
-
-    // Remove and open the target file
-    QFile file(fileName);
-    file.remove();
-    if (file.open(QFile::WriteOnly)) {
-        QCOMPARE(file.write(array), qint64(array.size()));
-        file.close();
-        QVERIFY(file.open(QFile::ReadOnly));
-        array.clear();
-        array = file.readAll();
-        file.remove();
-    } else {
-        QFAIL(qPrintable(QString("Couldn't open file for writing: [%1]").arg(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);
     }
-    // Check that we got the right content
-    QCOMPARE(array.size(), resizeSize);
-    for (int i = 0; i < array.size(); ++i) {
-        if (array[i] != char(i)) {
-            QFAIL(qPrintable(QString("Wrong contents! Char at %1 = %2, expected %3")
-                  .arg(i).arg(int(uchar(array[i]))).arg(int(uchar(i)))));
-        }
+
+    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()
@@ -2084,6 +2259,7 @@
 
     QFile file(source);
     QCOMPARE(file.rename(destination), result);
+
     if (result)
         QCOMPARE(file.error(), QFile::NoError);
     else
@@ -2212,6 +2388,7 @@
         QCOMPARE(readFile.read(1 << j).size(), 1 << j);
     }
 
+    readFile.close();
     QFile::remove(QLatin1String("appendfile.txt"));
 }
 
@@ -2336,13 +2513,13 @@
         }
 
         QByteArray ret = file.read(10);
-        QVERIFY(ret.isNull());
+        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.isNull());
+        QVERIFY(ret.isEmpty());
         QVERIFY(file.error() == QFile::NoError);
         QVERIFY(file.atEnd());
     }
@@ -2453,10 +2630,15 @@
     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::remove(fileName);
     }
     QFile file(fileName);
 
@@ -2495,8 +2677,13 @@
     QCOMPARE(file.error(), QFile::NoError);
 
     // hpux wont let you map multiple times.
-#if !defined(Q_OS_HPUX) && !defined(Q_USE_DEPRECATED_MAP_API)
+#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());
@@ -2532,7 +2719,6 @@
         QVERIFY(!memory);
         QVERIFY(file.setPermissions(originalPermissions));
     }
-
     QVERIFY(file.remove());
 }
 
@@ -2628,10 +2814,103 @@
 
 void tst_QFile::openDirectory()
 {
-    QFile f1("resources");
+    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 < 3; ++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);
+    }
 }
 
 QTEST_MAIN(tst_QFile)