0478b07006a5cdaffddd55b37dadb79bf286089c
[profile/ivi/qtbase.git] / tests / auto / corelib / io / qfile / tst_qfile.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43 #include <qplatformdefs.h>
44
45 #include <QCoreApplication>
46 #include <QDebug>
47 #include <QDir>
48 #include <QFile>
49 #include <QFileInfo>
50
51 #include <private/qabstractfileengine_p.h>
52 #include <private/qfsfileengine_p.h>
53
54 #ifdef Q_OS_WIN
55 QT_BEGIN_NAMESPACE
56 extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
57 QT_END_NAMESPACE
58 #endif
59
60 #if !defined(Q_OS_WINCE)
61 #include <QHostInfo>
62 #endif
63 #include <QProcess>
64 #ifdef Q_OS_WIN
65 # include <qt_windows.h>
66 #else
67 # include <sys/types.h>
68 # include <unistd.h>
69 #endif
70 #ifdef Q_OS_MAC
71 # include <sys/mount.h>
72 #elif defined(Q_OS_LINUX)
73 # include <sys/vfs.h>
74 #elif defined(Q_OS_FREEBSD)
75 # include <sys/param.h>
76 # include <sys/mount.h>
77 #elif defined(Q_OS_IRIX)
78 # include <sys/statfs.h>
79 #elif defined(Q_OS_WINCE)
80 # include <qplatformdefs.h>
81 #endif
82
83 #include <stdio.h>
84 #include <errno.h>
85
86 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
87 #include "../../../network-settings.h"
88 #endif
89
90 #ifndef STDIN_FILENO
91 #define STDIN_FILENO 0
92 #endif
93
94 #ifndef STDOUT_FILENO
95 #define STDOUT_FILENO 1
96 #endif
97
98 #ifndef STDERR_FILENO
99 #define STDERR_FILENO 2
100 #endif
101
102 #ifndef QT_OPEN_BINARY
103 #define QT_OPEN_BINARY 0
104 #endif
105
106 Q_DECLARE_METATYPE(QFile::FileError)
107
108 class tst_QFile : public QObject
109 {
110     Q_OBJECT
111
112 private slots:
113     void init();
114     void cleanup();
115     void initTestCase();
116     void cleanupTestCase();
117     void exists();
118     void open_data();
119     void open();
120     void openUnbuffered();
121     void size_data();
122     void size();
123     void sizeNoExist();
124     void seek();
125     void setSize();
126     void setSizeSeek();
127     void atEnd();
128     void readLine();
129     void readLine2();
130     void readLineNullInLine();
131     void readAll_data();
132     void readAll();
133     void readAllBuffer();
134     void readAllStdin();
135     void readLineStdin();
136     void readLineStdin_lineByLine();
137     void text();
138     void missingEndOfLine();
139     void readBlock();
140     void getch();
141     void ungetChar();
142     void createFile();
143     void append();
144     void permissions_data();
145     void permissions();
146     void permissionsNtfs_data();
147     void permissionsNtfs();
148     void setPermissions();
149     void copy();
150     void copyAfterFail();
151     void copyRemovesTemporaryFile() const;
152     void copyShouldntOverwrite();
153     void copyFallback();
154     void link();
155     void linkToDir();
156     void absolutePathLinkToRelativePath();
157     void readBrokenLink();
158     void readTextFile_data();
159     void readTextFile();
160     void readTextFile2();
161     void writeTextFile_data();
162     void writeTextFile();
163     /* void largeFileSupport(); */
164 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
165     void largeUncFileSupport();
166 #endif
167     void tailFile();
168     void flush();
169     void bufferedRead();
170     void isSequential();
171     void encodeName();
172     void truncate();
173     void seekToPos();
174     void seekAfterEndOfFile();
175     void FILEReadWrite();
176     void i18nFileName_data();
177     void i18nFileName();
178     void longFileName_data();
179     void longFileName();
180     void fileEngineHandler();
181 #ifdef QT_BUILD_INTERNAL
182     void useQFileInAFileHandler();
183 #endif
184     void getCharFF();
185     void remove_and_exists();
186     void removeOpenFile();
187     void fullDisk();
188     void writeLargeDataBlock_data();
189     void writeLargeDataBlock();
190     void readFromWriteOnlyFile();
191     void writeToReadOnlyFile();
192     void virtualFile();
193     void textFile();
194     void rename_data();
195     void rename();
196     void renameWithAtEndSpecialFile() const;
197     void renameFallback();
198     void renameMultiple();
199     void appendAndRead();
200     void miscWithUncPathAsCurrentDir();
201     void standarderror();
202     void handle();
203     void nativeHandleLeaks();
204
205     void readEof_data();
206     void readEof();
207
208     void map_data();
209     void map();
210     void mapResource_data();
211     void mapResource();
212     void mapOpenMode_data();
213     void mapOpenMode();
214
215     void openStandardStreamsFileDescriptors();
216     void openStandardStreamsBufferedStreams();
217
218     void resize_data();
219     void resize();
220
221     void objectConstructors();
222
223     void caseSensitivity();
224
225     void autocloseHandle();
226
227     void posAfterFailedStat();
228
229     void openDirectory();
230     void writeNothing();
231
232     void invalidFile_data();
233     void invalidFile();
234
235 private:
236     enum FileType {
237         OpenQFile,
238         OpenFd,
239         OpenStream,
240         NumberOfFileTypes
241     };
242
243     bool openFd(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags)
244     {
245         int fdMode = QT_OPEN_LARGEFILE | QT_OPEN_BINARY;
246
247         // File will be truncated if in Write mode.
248         if (mode & QIODevice::WriteOnly)
249             fdMode |= QT_OPEN_WRONLY | QT_OPEN_TRUNC;
250         if (mode & QIODevice::ReadOnly)
251             fdMode |= QT_OPEN_RDONLY;
252
253         fd_ = QT_OPEN(qPrintable(file.fileName()), fdMode);
254
255         return (-1 != fd_) && file.open(fd_, mode, handleFlags);
256     }
257
258     bool openStream(QFile &file, QIODevice::OpenMode mode, QFile::FileHandleFlags handleFlags)
259     {
260         char const *streamMode = "";
261
262         // File will be truncated if in Write mode.
263         if (mode & QIODevice::WriteOnly)
264             streamMode = "wb+";
265         else if (mode & QIODevice::ReadOnly)
266             streamMode = "rb";
267
268         stream_ = QT_FOPEN(qPrintable(file.fileName()), streamMode);
269
270         return stream_ && file.open(stream_, mode, handleFlags);
271     }
272
273     bool openFile(QFile &file, QIODevice::OpenMode mode, FileType type = OpenQFile, QFile::FileHandleFlags handleFlags = QFile::DontCloseHandle)
274     {
275         if (mode & QIODevice::WriteOnly && !file.exists())
276         {
277             // Make sure the file exists
278             QFile createFile(file.fileName());
279             if (!createFile.open(QIODevice::ReadWrite))
280                 return false;
281         }
282
283         // Note: openFd and openStream will truncate the file if write mode.
284         switch (type)
285         {
286             case OpenQFile:
287                 return file.open(mode);
288
289             case OpenFd:
290                 return openFd(file, mode, handleFlags);
291
292             case OpenStream:
293                 return openStream(file, mode, handleFlags);
294
295             case NumberOfFileTypes:
296                 break;
297         }
298
299         return false;
300     }
301
302     void closeFile(QFile &file)
303     {
304         file.close();
305
306         if (-1 != fd_)
307             QT_CLOSE(fd_);
308         if (stream_)
309             ::fclose(stream_);
310
311         fd_ = -1;
312         stream_ = 0;
313     }
314
315     int fd_;
316     FILE *stream_;
317 };
318
319 void tst_QFile::init()
320 {
321     fd_ = -1;
322     stream_ = 0;
323 }
324
325 void tst_QFile::cleanup()
326 {
327     // for copyFallback()
328     if (QFile::exists("file-copy-destination.txt")) {
329         QFile::setPermissions("file-copy-destination.txt",
330                 QFile::ReadOwner | QFile::WriteOwner);
331         QFile::remove("file-copy-destination.txt");
332     }
333
334     // for renameFallback()
335     QFile::remove("file-rename-destination.txt");
336
337     // for copyAfterFail()
338     QFile::remove("file-to-be-copied.txt");
339     QFile::remove("existing-file.txt");
340     QFile::remove("copied-file-1.txt");
341     QFile::remove("copied-file-2.txt");
342
343     // for renameMultiple()
344     QFile::remove("file-to-be-renamed.txt");
345     QFile::remove("existing-file.txt");
346     QFile::remove("file-renamed-once.txt");
347     QFile::remove("file-renamed-twice.txt");
348
349     if (-1 != fd_)
350         QT_CLOSE(fd_);
351     if (stream_)
352         ::fclose(stream_);
353 }
354
355 void tst_QFile::initTestCase()
356 {
357     QString workingDir = QFileInfo(QFINDTESTDATA("stdinprocess")).absolutePath();
358     QVERIFY2(!workingDir.isEmpty(), qPrintable("Could not find working directory!"));
359     QVERIFY2(QDir::setCurrent(workingDir), qPrintable("Could not chdir to " + workingDir));
360
361     QFile::remove("noreadfile");
362
363     // create a file and make it read-only
364     QFile file("readonlyfile");
365     file.open(QFile::WriteOnly);
366     file.write("a", 1);
367     file.close();
368     file.setPermissions(QFile::ReadOwner);
369
370     // create another file and make it not readable
371     file.setFileName("noreadfile");
372     file.open(QFile::WriteOnly);
373     file.write("b", 1);
374     file.close();
375     file.setPermissions(0);
376 }
377
378 void tst_QFile::cleanupTestCase()
379 {
380     // clean up the files we created
381     QFile::remove("readonlyfile");
382     QFile::remove("noreadfile");
383     QFile::remove("myLink.lnk");
384     QFile::remove("appendme.txt");
385     QFile::remove("createme.txt");
386     QFile::remove("file.txt");
387     QFile::remove("genfile.txt");
388     QFile::remove("seekToPos.txt");
389     QFile::remove("setsizeseek.txt");
390     QFile::remove("stdfile.txt");
391     QFile::remove("textfile.txt");
392     QFile::remove("truncate.txt");
393     QFile::remove("winfile.txt");
394     QFile::remove("writeonlyfile");
395     QFile::remove("largeblockfile.txt");
396     QFile::remove("tst_qfile_copy.cpp");
397     QFile::remove("nullinline.txt");
398     QFile::remove("myLink2.lnk");
399     QFile::remove("resources");
400     QFile::remove("qfile_map_testfile");
401     QFile::remove("readAllBuffer.txt");
402     QFile::remove("qt_file.tmp");
403     QFile::remove("File.txt");
404 }
405
406 //------------------------------------------
407 // The 'testfile' is currently just a
408 // testfile. The path of this file, the
409 // attributes and the contents itself
410 // will be changed as far as we have a
411 // proper way to handle files in the
412 // testing environment.
413 //------------------------------------------
414
415 void tst_QFile::exists()
416 {
417     QFile f( QFINDTESTDATA("testfile.txt") );
418     QVERIFY(f.exists());
419
420     QFile file("nobodyhassuchafile");
421     file.remove();
422     QVERIFY(!file.exists());
423
424     QFile file2("nobodyhassuchafile");
425     QVERIFY(file2.open(QIODevice::WriteOnly));
426     file2.close();
427
428     QVERIFY(file.exists());
429
430     QVERIFY(file.open(QIODevice::WriteOnly));
431     file.close();
432     QVERIFY(file.exists());
433
434     file.remove();
435     QVERIFY(!file.exists());
436
437 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
438     QFile unc("//" + QtNetworkSettings::winServerName() + "/testshare/readme.txt");
439     QVERIFY(unc.exists());
440 #endif
441 }
442
443 void tst_QFile::open_data()
444 {
445     QTest::addColumn<QString>("filename");
446     QTest::addColumn<int>("mode");
447     QTest::addColumn<bool>("ok");
448     QTest::addColumn<QFile::FileError>("status");
449
450 #ifdef Q_OS_MAC
451     static const QString denied("Operation not permitted");
452 #else
453     static const QString denied("Permission denied");
454 #endif
455     QTest::newRow( "exist_readOnly"  )
456         << QString(QFINDTESTDATA("testfile.txt")) << int(QIODevice::ReadOnly)
457         << true << QFile::NoError;
458
459     QTest::newRow( "exist_writeOnly" )
460         << QString("readonlyfile")
461         << int(QIODevice::WriteOnly)
462         << false
463         << QFile::OpenError;
464
465     QTest::newRow( "exist_append"    )
466         << QString("readonlyfile") << int(QIODevice::Append)
467         << false << QFile::OpenError;
468
469     QTest::newRow( "nonexist_readOnly"  )
470         << QString("nonExist.txt") << int(QIODevice::ReadOnly)
471         << false << QFile::OpenError;
472
473     QTest::newRow("emptyfile")
474         << QString("")
475         << int(QIODevice::ReadOnly)
476         << false
477         << QFile::OpenError;
478
479     QTest::newRow("nullfile") << QString() << int(QIODevice::ReadOnly) << false
480         << QFile::OpenError;
481
482     QTest::newRow("two-dots") << QString(QFINDTESTDATA("two.dots.file")) << int(QIODevice::ReadOnly) << true
483         << QFile::NoError;
484
485     QTest::newRow("readonlyfile") << QString("readonlyfile") << int(QIODevice::WriteOnly)
486                                   << false << QFile::OpenError;
487     QTest::newRow("noreadfile") << QString("noreadfile") << int(QIODevice::ReadOnly)
488                                 << false << QFile::OpenError;
489 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
490     //opening devices requires administrative privileges (and elevation).
491     HANDLE hTest = CreateFile(_T("\\\\.\\PhysicalDrive0"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
492     if (hTest != INVALID_HANDLE_VALUE) {
493         CloseHandle(hTest);
494         QTest::newRow("//./PhysicalDrive0") << QString("//./PhysicalDrive0") << int(QIODevice::ReadOnly)
495                                             << true << QFile::NoError;
496     } else {
497         QTest::newRow("//./PhysicalDrive0") << QString("//./PhysicalDrive0") << int(QIODevice::ReadOnly)
498                                             << false << QFile::OpenError;
499     }
500     QTest::newRow("uncFile") << "//" + QtNetworkSettings::winServerName() + "/testshare/test.pri" << int(QIODevice::ReadOnly)
501                              << true << QFile::NoError;
502 #endif
503 }
504
505 void tst_QFile::open()
506 {
507     QFETCH( QString, filename );
508     QFETCH( int, mode );
509
510     QFile f( filename );
511
512     QFETCH( bool, ok );
513
514 #if defined(Q_OS_UNIX)
515     if (::getuid() == 0)
516         // root and Chuck Norris don't care for file permissions. Skip.
517         QSKIP("Running this test as root doesn't make sense");
518 #endif
519
520 #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
521     QEXPECT_FAIL("noreadfile", "Windows does not currently support non-readable files.", Abort);
522 #endif
523     if (filename.isEmpty())
524         QTest::ignoreMessage(QtWarningMsg, "QFSFileEngine::open: No file name specified");
525
526     QCOMPARE(f.open( QIODevice::OpenMode(mode) ), ok);
527
528     QTEST( f.error(), "status" );
529 }
530
531 void tst_QFile::openUnbuffered()
532 {
533     QFile file(QFINDTESTDATA("testfile.txt"));
534     QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered));
535     char c = '\0';
536     QVERIFY(file.seek(1));
537     QCOMPARE(file.pos(), qint64(1));
538     QVERIFY(file.getChar(&c));
539     QCOMPARE(file.pos(), qint64(2));
540     char d = '\0';
541     QVERIFY(file.seek(3));
542     QCOMPARE(file.pos(), qint64(3));
543     QVERIFY(file.getChar(&d));
544     QCOMPARE(file.pos(), qint64(4));
545     QVERIFY(file.seek(1));
546     QCOMPARE(file.pos(), qint64(1));
547     char c2 = '\0';
548     QVERIFY(file.getChar(&c2));
549     QCOMPARE(file.pos(), qint64(2));
550     QVERIFY(file.seek(3));
551     QCOMPARE(file.pos(), qint64(3));
552     char d2 = '\0';
553     QVERIFY(file.getChar(&d2));
554     QCOMPARE(file.pos(), qint64(4));
555     QCOMPARE(c, c2);
556     QCOMPARE(d, d2);
557     QCOMPARE(c, '-');
558     QCOMPARE(d, '-');
559 }
560
561 void tst_QFile::size_data()
562 {
563     QTest::addColumn<QString>("filename");
564     QTest::addColumn<qint64>("size");
565
566     QTest::newRow( "exist01" ) << QString(QFINDTESTDATA("testfile.txt")) << (qint64)245;
567 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
568     // Only test UNC on Windows./
569     QTest::newRow("unc") << "//" + QString(QtNetworkSettings::winServerName() + "/testshare/test.pri") << (qint64)34;
570 #endif
571 }
572
573 void tst_QFile::size()
574 {
575     QFETCH( QString, filename );
576     QFETCH( qint64, size );
577
578 #ifdef Q_OS_WINCE
579         filename = QFileInfo(filename).absoluteFilePath();
580 #endif
581
582     {
583         QFile f( filename );
584         QCOMPARE( f.size(), size );
585
586         QVERIFY( f.open(QIODevice::ReadOnly) );
587         QCOMPARE( f.size(), size );
588     }
589
590     {
591         QFile f;
592         FILE* stream = QT_FOPEN(filename.toLocal8Bit().constData(), "rb");
593         QVERIFY( stream );
594         QVERIFY( f.open(stream, QIODevice::ReadOnly) );
595         QCOMPARE( f.size(), size );
596
597         f.close();
598         fclose(stream);
599     }
600
601     // Currently low level file I/O is not well supported on Windows CE, so
602     // skip this part of the test.
603 #ifndef Q_OS_WINCE
604     {
605         QFile f;
606
607         int fd = QT_OPEN(filename.toLocal8Bit().constData(), QT_OPEN_RDONLY);
608
609         QVERIFY( fd != -1 );
610         QVERIFY( f.open(fd, QIODevice::ReadOnly) );
611         QCOMPARE( f.size(), size );
612
613         f.close();
614         QT_CLOSE(fd);
615     }
616 #endif
617 }
618
619 void tst_QFile::sizeNoExist()
620 {
621     QFile file("nonexist01");
622     QVERIFY( !file.exists() );
623     QCOMPARE( file.size(), (qint64)0 );
624     QVERIFY( !file.open(QIODevice::ReadOnly) );
625 }
626
627 void tst_QFile::seek()
628 {
629     QFile::remove("newfile.txt");
630     QFile file("newfile.txt");
631     file.open(QIODevice::WriteOnly);
632     QCOMPARE(file.size(), qint64(0));
633     QCOMPARE(file.pos(), qint64(0));
634     QVERIFY(file.seek(10));
635     QCOMPARE(file.pos(), qint64(10));
636     QCOMPARE(file.size(), qint64(0));
637     file.close();
638     QFile::remove("newfile.txt");
639 }
640
641 void tst_QFile::setSize()
642 {
643     if ( QFile::exists( "createme.txt" ) )
644         QFile::remove( "createme.txt" );
645     QVERIFY( !QFile::exists( "createme.txt" ) );
646
647     QFile f("createme.txt");
648     QVERIFY(f.open(QIODevice::Truncate | QIODevice::ReadWrite));
649     f.putChar('a');
650
651     f.seek(0);
652     char c = '\0';
653     f.getChar(&c);
654     QCOMPARE(c, 'a');
655
656     QCOMPARE(f.size(), (qlonglong)1);
657     bool ok = f.resize(99);
658     QVERIFY(ok);
659     QCOMPARE(f.size(), (qlonglong)99);
660
661     f.seek(0);
662     c = '\0';
663     f.getChar(&c);
664     QCOMPARE(c, 'a');
665
666     QVERIFY(f.resize(1));
667     QCOMPARE(f.size(), (qlonglong)1);
668
669     f.seek(0);
670     c = '\0';
671     f.getChar(&c);
672     QCOMPARE(c, 'a');
673
674     f.close();
675
676     QCOMPARE(f.size(), (qlonglong)1);
677     QVERIFY(f.resize(100));
678     QCOMPARE(f.size(), (qlonglong)100);
679     QVERIFY(f.resize(50));
680     QCOMPARE(f.size(), (qlonglong)50);
681 }
682
683 void tst_QFile::setSizeSeek()
684 {
685     QFile::remove("setsizeseek.txt");
686     QFile f("setsizeseek.txt");
687     QVERIFY(f.open(QFile::WriteOnly));
688     f.write("ABCD");
689
690     QCOMPARE(f.pos(), qint64(4));
691     f.resize(2);
692     QCOMPARE(f.pos(), qint64(2));
693     f.resize(4);
694     QCOMPARE(f.pos(), qint64(2));
695     f.resize(0);
696     QCOMPARE(f.pos(), qint64(0));
697     f.resize(4);
698     QCOMPARE(f.pos(), qint64(0));
699
700     f.seek(3);
701     QCOMPARE(f.pos(), qint64(3));
702     f.resize(2);
703     QCOMPARE(f.pos(), qint64(2));
704 }
705
706 void tst_QFile::atEnd()
707 {
708     QFile f( QFINDTESTDATA("testfile.txt") );
709     QVERIFY(f.open( QIODevice::ReadOnly ));
710
711     int size = f.size();
712     f.seek( size );
713
714     bool end = f.atEnd();
715     f.close();
716     QVERIFY(end);
717 }
718
719 void tst_QFile::readLine()
720 {
721     QFile f( QFINDTESTDATA("testfile.txt") );
722     QVERIFY(f.open( QIODevice::ReadOnly ));
723
724     int i = 0;
725     char p[128];
726     int foo;
727     while ( (foo=f.readLine( p, 128 )) > 0 ) {
728         ++i;
729         if ( i == 5 ) {
730             QCOMPARE( p[0], 'T' );
731             QCOMPARE( p[3], 's' );
732             QCOMPARE( p[11], 'i' );
733         }
734     }
735     f.close();
736     QCOMPARE( i, 6 );
737 }
738
739 void tst_QFile::readLine2()
740 {
741     QFile f( QFINDTESTDATA("testfile.txt") );
742     f.open( QIODevice::ReadOnly );
743
744     char p[128];
745     QCOMPARE(f.readLine(p, 60), qlonglong(59));
746     QCOMPARE(f.readLine(p, 60), qlonglong(59));
747     memset(p, '@', sizeof(p));
748     QCOMPARE(f.readLine(p, 60), qlonglong(59));
749
750     QCOMPARE(p[57], '-');
751     QCOMPARE(p[58], '\n');
752     QCOMPARE(p[59], '\0');
753     QCOMPARE(p[60], '@');
754 }
755
756 void tst_QFile::readLineNullInLine()
757 {
758     QFile::remove("nullinline.txt");
759     QFile file("nullinline.txt");
760     QVERIFY(file.open(QIODevice::ReadWrite));
761     QVERIFY(file.write("linewith\0null\nanotherline\0withnull\n\0\nnull\0", 42) > 0);
762     QVERIFY(file.flush());
763     file.reset();
764
765     QCOMPARE(file.readLine(), QByteArray("linewith\0null\n", 14));
766     QCOMPARE(file.readLine(), QByteArray("anotherline\0withnull\n", 21));
767     QCOMPARE(file.readLine(), QByteArray("\0\n", 2));
768     QCOMPARE(file.readLine(), QByteArray("null\0", 5));
769     QCOMPARE(file.readLine(), QByteArray());
770 }
771
772 void tst_QFile::readAll_data()
773 {
774     QTest::addColumn<bool>("textMode");
775     QTest::addColumn<QString>("fileName");
776     QTest::newRow( "TextMode unixfile" ) <<  true << QFINDTESTDATA("testfile.txt");
777     QTest::newRow( "BinaryMode unixfile" ) <<  false << QFINDTESTDATA("testfile.txt");
778     QTest::newRow( "TextMode dosfile" ) <<  true << QFINDTESTDATA("dosfile.txt");
779     QTest::newRow( "BinaryMode dosfile" ) <<  false << QFINDTESTDATA("dosfile.txt");
780     QTest::newRow( "TextMode bigfile" ) <<  true << QFINDTESTDATA("tst_qfile.cpp");
781     QTest::newRow( "BinaryMode  bigfile" ) <<  false << QFINDTESTDATA("tst_qfile.cpp");
782     QVERIFY(QFile(QFINDTESTDATA("tst_qfile.cpp")).size() > 64*1024);
783 }
784
785 void tst_QFile::readAll()
786 {
787     QFETCH( bool, textMode );
788     QFETCH( QString, fileName );
789
790     QFile file(fileName);
791     if (textMode)
792         QVERIFY(file.open(QFile::Text | QFile::ReadOnly));
793     else
794         QVERIFY(file.open(QFile::ReadOnly));
795
796     QByteArray a = file.readAll();
797     file.reset();
798     QVERIFY(file.pos() == 0);
799
800     QVERIFY(file.bytesAvailable() > 7);
801     QByteArray b = file.read(1);
802     char x;
803     file.getChar(&x);
804     b.append(x);
805     b.append(file.read(5));
806     b.append(file.readAll());
807
808     QCOMPARE(a, b);
809 }
810
811 void tst_QFile::readAllBuffer()
812 {
813     QString fileName = QLatin1String("readAllBuffer.txt");
814
815     QFile::remove(fileName);
816
817     QFile writer(fileName);
818     QFile reader(fileName);
819
820     QByteArray data1("This is arguably a very simple text.");
821     QByteArray data2("This is surely not as simple a test.");
822
823     QVERIFY( writer.open(QIODevice::ReadWrite | QIODevice::Unbuffered) );
824     QVERIFY( reader.open(QIODevice::ReadOnly) );
825
826     QCOMPARE( writer.write(data1), qint64(data1.size()) );
827     QVERIFY( writer.seek(0) );
828
829     QByteArray result;
830     result = reader.read(18);
831     QCOMPARE( result.size(), 18 );
832
833     QCOMPARE( writer.write(data2), qint64(data2.size()) ); // new data, old version buffered in reader
834     QCOMPARE( writer.write(data2), qint64(data2.size()) ); // new data, unbuffered in reader
835
836     result += reader.readAll();
837
838     QCOMPARE( result, data1 + data2 );
839
840     QFile::remove(fileName);
841 }
842
843 void tst_QFile::readAllStdin()
844 {
845 #if defined(Q_OS_WINCE)
846     QSKIP("Currently no stdin/out supported for Windows CE");
847 #endif
848 #if defined(QT_NO_PROCESS)
849     QSKIP("Qt was compiled with QT_NO_PROCESS");
850 #else
851     QByteArray lotsOfData(1024, '@'); // 10 megs
852
853     QProcess process;
854     process.start("stdinprocess/stdinprocess all");
855     QVERIFY( process.waitForStarted() );
856     for (int i = 0; i < 5; ++i) {
857         QTest::qWait(1000);
858         process.write(lotsOfData);
859         while (process.bytesToWrite() > 0) {
860             QVERIFY(process.waitForBytesWritten());
861         }
862     }
863
864     process.closeWriteChannel();
865     process.waitForFinished();
866     QCOMPARE(process.readAll().size(), lotsOfData.size() * 5);
867 #endif
868 }
869
870 void tst_QFile::readLineStdin()
871 {
872 #if defined(Q_OS_WINCE)
873     QSKIP("Currently no stdin/out supported for Windows CE");
874 #endif
875 #if defined(QT_NO_PROCESS)
876     QSKIP("Qt was compiled with QT_NO_PROCESS");
877 #else
878
879     QByteArray lotsOfData(1024, '@'); // 10 megs
880     for (int i = 0; i < lotsOfData.size(); ++i) {
881         if ((i % 32) == 31)
882             lotsOfData[i] = '\n';
883         else
884             lotsOfData[i] = char('0' + i % 32);
885     }
886
887     for (int i = 0; i < 2; ++i) {
888         QProcess process;
889         process.start((QString("stdinprocess/stdinprocess line %1").arg(i)), QIODevice::Text | QIODevice::ReadWrite);
890         for (int i = 0; i < 5; ++i) {
891             QTest::qWait(1000);
892             process.write(lotsOfData);
893             while (process.bytesToWrite() > 0) {
894                 QVERIFY(process.waitForBytesWritten());
895             }
896         }
897
898         process.closeWriteChannel();
899         QVERIFY(process.waitForFinished(5000));
900
901         QByteArray array = process.readAll();
902         QCOMPARE(array.size(), lotsOfData.size() * 5);
903         for (int i = 0; i < array.size(); ++i) {
904             if ((i % 32) == 31)
905                 QCOMPARE(char(array[i]), '\n');
906             else
907                 QCOMPARE(char(array[i]), char('0' + i % 32));
908         }
909     }
910 #endif
911 }
912
913 void tst_QFile::readLineStdin_lineByLine()
914 {
915 #if defined(Q_OS_WINCE)
916     QSKIP("Currently no stdin/out supported for Windows CE");
917 #endif
918 #if defined(QT_NO_PROCESS)
919     QSKIP("Qt was compiled with QT_NO_PROCESS");
920 #else
921     for (int i = 0; i < 2; ++i) {
922         QProcess process;
923         process.start(QString("stdinprocess/stdinprocess line %1").arg(i), QIODevice::Text | QIODevice::ReadWrite);
924         QVERIFY(process.waitForStarted());
925
926         for (int j = 0; j < 3; ++j) {
927             QByteArray line = "line " + QByteArray::number(j) + "\n";
928             QCOMPARE(process.write(line), qint64(line.size()));
929             QVERIFY(process.waitForBytesWritten(2000));
930             if (process.bytesAvailable() == 0)
931                 QVERIFY(process.waitForReadyRead(2000));
932             QCOMPARE(process.readAll(), line);
933         }
934
935         process.closeWriteChannel();
936         QVERIFY(process.waitForFinished(5000));
937     }
938 #endif
939 }
940
941 void tst_QFile::text()
942 {
943     // dosfile.txt is a binary CRLF file
944     QFile file(QFINDTESTDATA("dosfile.txt"));
945     QVERIFY(file.open(QFile::Text | QFile::ReadOnly));
946     QCOMPARE(file.readLine(),
947             QByteArray("/dev/system/root     /                    reiserfs   acl,user_xattr        1 1\n"));
948     QCOMPARE(file.readLine(),
949             QByteArray("/dev/sda1            /boot                ext3       acl,user_xattr        1 2\n"));
950     file.ungetChar('\n');
951     file.ungetChar('2');
952     QCOMPARE(file.readLine().constData(), QByteArray("2\n").constData());
953 }
954
955 void tst_QFile::missingEndOfLine()
956 {
957     QFile file(QFINDTESTDATA("noendofline.txt"));
958     QVERIFY(file.open(QFile::ReadOnly));
959
960     int nlines = 0;
961     while (!file.atEnd()) {
962         ++nlines;
963         file.readLine();
964     }
965
966     QCOMPARE(nlines, 3);
967 }
968
969 void tst_QFile::readBlock()
970 {
971     QFile f( QFINDTESTDATA("testfile.txt") );
972     f.open( QIODevice::ReadOnly );
973
974     int length = 0;
975     char p[256];
976     length = f.read( p, 256 );
977     f.close();
978     QCOMPARE( length, 245 );
979     QCOMPARE( p[59], 'D' );
980     QCOMPARE( p[178], 'T' );
981     QCOMPARE( p[199], 'l' );
982 }
983
984 void tst_QFile::getch()
985 {
986     QFile f( QFINDTESTDATA("testfile.txt") );
987     f.open( QIODevice::ReadOnly );
988
989     char c;
990     int i = 0;
991     while (f.getChar(&c)) {
992         QCOMPARE(f.pos(), qint64(i + 1));
993         if ( i == 59 )
994             QCOMPARE( c, 'D' );
995         ++i;
996     }
997     f.close();
998     QCOMPARE( i, 245 );
999 }
1000
1001 void tst_QFile::ungetChar()
1002 {
1003     QFile f(QFINDTESTDATA("testfile.txt"));
1004     QVERIFY(f.open(QIODevice::ReadOnly));
1005
1006     QByteArray array = f.readLine();
1007     QCOMPARE(array.constData(), "----------------------------------------------------------\n");
1008     f.ungetChar('\n');
1009
1010     array = f.readLine();
1011     QCOMPARE(array.constData(), "\n");
1012
1013     f.ungetChar('\n');
1014     f.ungetChar('-');
1015     f.ungetChar('-');
1016
1017     array = f.readLine();
1018     QCOMPARE(array.constData(), "--\n");
1019
1020     QFile::remove("genfile.txt");
1021     QFile out("genfile.txt");
1022     QVERIFY(out.open(QIODevice::ReadWrite));
1023     out.write("123");
1024     out.seek(0);
1025     QCOMPARE(out.readAll().constData(), "123");
1026     out.ungetChar('3');
1027     out.write("4");
1028     out.seek(0);
1029     QCOMPARE(out.readAll().constData(), "124");
1030     out.ungetChar('4');
1031     out.ungetChar('2');
1032     out.ungetChar('1');
1033     char buf[3];
1034     QCOMPARE(out.read(buf, sizeof(buf)), qint64(3));
1035     QCOMPARE(buf[0], '1');
1036     QCOMPARE(buf[1], '2');
1037     QCOMPARE(buf[2], '4');
1038 }
1039
1040 void tst_QFile::invalidFile_data()
1041 {
1042     QTest::addColumn<QString>("fileName");
1043 #if !defined(Q_OS_WIN)
1044     QTest::newRow( "x11" ) << QString( "qwe//" );
1045 #else
1046     QTest::newRow( "colon1" ) << QString( "fail:invalid" );
1047     QTest::newRow( "colon2" ) << QString( "f:ail:invalid" );
1048     QTest::newRow( "colon3" ) << QString( ":failinvalid" );
1049     QTest::newRow( "forwardslash" ) << QString( "fail/invalid" );
1050     QTest::newRow( "asterisk" ) << QString( "fail*invalid" );
1051     QTest::newRow( "questionmark" ) << QString( "fail?invalid" );
1052     QTest::newRow( "quote" ) << QString( "fail\"invalid" );
1053     QTest::newRow( "lt" ) << QString( "fail<invalid" );
1054     QTest::newRow( "gt" ) << QString( "fail>invalid" );
1055     QTest::newRow( "pipe" ) << QString( "fail|invalid" );
1056 #endif
1057 }
1058
1059 void tst_QFile::invalidFile()
1060 {
1061     QFETCH( QString, fileName );
1062     QFile f( fileName );
1063     QEXPECT_FAIL("colon1", "QTBUG-27306", Continue);
1064     QVERIFY( !f.open( QIODevice::ReadWrite ) );
1065 }
1066
1067 void tst_QFile::createFile()
1068 {
1069     if ( QFile::exists( "createme.txt" ) )
1070         QFile::remove( "createme.txt" );
1071     QVERIFY( !QFile::exists( "createme.txt" ) );
1072
1073     QFile f( "createme.txt" );
1074     QVERIFY( f.open( QIODevice::WriteOnly ) );
1075     f.close();
1076     QVERIFY( QFile::exists( "createme.txt" ) );
1077 }
1078
1079 void tst_QFile::append()
1080 {
1081     const QString name("appendme.txt");
1082     if (QFile::exists(name))
1083         QFile::remove(name);
1084     QVERIFY(!QFile::exists(name));
1085
1086     QFile f(name);
1087     QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate));
1088     f.putChar('a');
1089     f.close();
1090
1091     QVERIFY(f.open(QIODevice::Append));
1092     QVERIFY(f.pos() == 1);
1093     f.putChar('a');
1094     f.close();
1095     QCOMPARE(int(f.size()), 2);
1096 }
1097
1098 void tst_QFile::permissions_data()
1099 {
1100     QTest::addColumn<QString>("file");
1101     QTest::addColumn<uint>("perms");
1102     QTest::addColumn<bool>("expected");
1103     QTest::addColumn<bool>("create");
1104
1105     QTest::newRow("data0") << QCoreApplication::instance()->applicationFilePath() << uint(QFile::ExeUser) << true << false;
1106     QTest::newRow("data1") << QFINDTESTDATA("tst_qfile.cpp") << uint(QFile::ReadUser) << true << false;
1107     QTest::newRow("readonly") << QFINDTESTDATA("readonlyfile") << uint(QFile::WriteUser) << false << false;
1108 #ifndef Q_OS_WINCE
1109     QTest::newRow("longfile") << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
1110                                                     "longFileNamelongFileNamelongFileNamelongFileName"
1111                                                     "longFileNamelongFileNamelongFileNamelongFileName"
1112                                                     "longFileNamelongFileNamelongFileNamelongFileName"
1113                                                     "longFileNamelongFileNamelongFileNamelongFileName.txt") << uint(QFile::ReadUser) << true << true;
1114 #endif
1115     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ReadUser) << true << false;
1116     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::WriteUser) << false << false;
1117     QTest::newRow("resource3") << ":/tst_qfileinfo/resources/file1.ext1" << uint(QFile::ExeUser) << false << false;
1118 }
1119
1120 void tst_QFile::permissions()
1121 {
1122     QFETCH(QString, file);
1123     QFETCH(uint, perms);
1124     QFETCH(bool, expected);
1125     QFETCH(bool, create);
1126     if (create) {
1127         QFile fc(file);
1128         QVERIFY(fc.open(QFile::WriteOnly));
1129         QVERIFY(fc.write("hello\n"));
1130         fc.close();
1131     }
1132
1133     QFile f(file);
1134     QFile::Permissions memberResult = f.permissions() & perms;
1135     QFile::Permissions staticResult = QFile::permissions(file) & perms;
1136
1137     if (create) {
1138         QFile::remove(file);
1139     }
1140
1141 #ifdef Q_OS_WIN
1142     if (qt_ntfs_permission_lookup)
1143         QEXPECT_FAIL("readonly", "QTBUG-25630", Abort);
1144 #endif
1145     QCOMPARE((memberResult == QFile::Permissions(perms)), expected);
1146     QCOMPARE((staticResult == QFile::Permissions(perms)), expected);
1147 }
1148
1149 void tst_QFile::permissionsNtfs_data()
1150 {
1151     permissions_data();
1152 }
1153
1154 void tst_QFile::permissionsNtfs()
1155 {
1156 #ifdef Q_OS_WIN
1157     QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup);
1158     qt_ntfs_permission_lookup++;
1159     permissions();
1160 #else
1161     QSKIP("windows test");
1162 #endif
1163 }
1164
1165 void tst_QFile::setPermissions()
1166 {
1167     if ( QFile::exists( "createme.txt" ) )
1168         QFile::remove( "createme.txt" );
1169     QVERIFY( !QFile::exists( "createme.txt" ) );
1170
1171     QFile f("createme.txt");
1172     QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate));
1173     f.putChar('a');
1174     f.close();
1175
1176     QFile::Permissions perms(QFile::WriteUser | QFile::ReadUser);
1177     QVERIFY(f.setPermissions(perms));
1178     QVERIFY((f.permissions() & perms) == perms);
1179
1180 }
1181
1182 void tst_QFile::copy()
1183 {
1184     QFile::setPermissions("tst_qfile_copy.cpp", QFile::WriteUser);
1185     QFile::remove("tst_qfile_copy.cpp");
1186     QFile::remove("test2");
1187     QVERIFY(QFile::copy(QFINDTESTDATA("tst_qfile.cpp"), "tst_qfile_copy.cpp"));
1188     QFile in1(QFINDTESTDATA("tst_qfile.cpp")), in2("tst_qfile_copy.cpp");
1189     QVERIFY(in1.open(QFile::ReadOnly));
1190     QVERIFY(in2.open(QFile::ReadOnly));
1191     QByteArray data1 = in1.readAll(), data2 = in2.readAll();
1192     QCOMPARE(data1, data2);
1193     QFile::remove( "main_copy.cpp" );
1194
1195     QFile::copy(QDir::currentPath(), QDir::currentPath() + QLatin1String("/test2"));
1196 }
1197
1198 void tst_QFile::copyAfterFail()
1199 {
1200     QFile file1("file-to-be-copied.txt");
1201     QFile file2("existing-file.txt");
1202
1203     QVERIFY(file1.open(QIODevice::ReadWrite) && "(test-precondition)");
1204     QVERIFY(file2.open(QIODevice::ReadWrite) && "(test-precondition)");
1205     file2.close();
1206     QVERIFY(!QFile::exists("copied-file-1.txt") && "(test-precondition)");
1207     QVERIFY(!QFile::exists("copied-file-2.txt") && "(test-precondition)");
1208
1209     QVERIFY(!file1.copy("existing-file.txt"));
1210     QCOMPARE(file1.error(), QFile::CopyError);
1211
1212     QVERIFY(file1.copy("copied-file-1.txt"));
1213     QVERIFY(!file1.isOpen());
1214     QCOMPARE(file1.error(), QFile::NoError);
1215
1216     QVERIFY(!file1.copy("existing-file.txt"));
1217     QCOMPARE(file1.error(), QFile::CopyError);
1218
1219     QVERIFY(file1.copy("copied-file-2.txt"));
1220     QVERIFY(!file1.isOpen());
1221     QCOMPARE(file1.error(), QFile::NoError);
1222
1223     QVERIFY(QFile::exists("copied-file-1.txt"));
1224     QVERIFY(QFile::exists("copied-file-2.txt"));
1225
1226     QVERIFY(QFile::remove("file-to-be-copied.txt") && "(test-cleanup)");
1227     QVERIFY(QFile::remove("existing-file.txt") && "(test-cleanup)");
1228     QVERIFY(QFile::remove("copied-file-1.txt") && "(test-cleanup)");
1229     QVERIFY(QFile::remove("copied-file-2.txt") && "(test-cleanup)");
1230 }
1231
1232 void tst_QFile::copyRemovesTemporaryFile() const
1233 {
1234     const QString newName(QLatin1String("copyRemovesTemporaryFile"));
1235     QVERIFY(QFile::copy(QFINDTESTDATA("forCopying.txt"), newName));
1236
1237     QVERIFY(!QFile::exists(QFINDTESTDATA("qt_temp.XXXXXX")));
1238     QVERIFY(QFile::remove(newName));
1239 }
1240
1241 void tst_QFile::copyShouldntOverwrite()
1242 {
1243     // Copy should not overwrite existing files.
1244     QFile::remove("tst_qfile.cpy");
1245     QFile file(QFINDTESTDATA("tst_qfile.cpp"));
1246     QVERIFY(file.copy("tst_qfile.cpy"));
1247
1248     bool ok = QFile::setPermissions("tst_qfile.cpy", QFile::WriteOther);
1249     QVERIFY(ok);
1250     QVERIFY(!file.copy("tst_qfile.cpy"));
1251     QFile::remove("tst_qfile.cpy");
1252 }
1253
1254 void tst_QFile::copyFallback()
1255 {
1256     // Using a resource file to trigger QFile::copy's fallback handling
1257     QFile file(":/copy-fallback.qrc");
1258     QFile::remove("file-copy-destination.txt");
1259
1260     QVERIFY2(file.exists(), "test precondition");
1261     QVERIFY2(!QFile::exists("file-copy-destination.txt"), "test precondition");
1262
1263     // Fallback copy of closed file.
1264     QVERIFY(file.copy("file-copy-destination.txt"));
1265     QVERIFY(QFile::exists("file-copy-destination.txt"));
1266     QVERIFY(!file.isOpen());
1267
1268 #ifdef Q_OS_WINCE
1269     // Need to reset permissions on Windows to be able to delete
1270     QVERIFY(QFile::setPermissions("file-copy-destination.txt",
1271             QFile::WriteOther));
1272 #else
1273      // Need to reset permissions on Windows to be able to delete
1274     QVERIFY(QFile::setPermissions("file-copy-destination.txt",
1275            QFile::ReadOwner | QFile::WriteOwner));
1276 #endif
1277     QVERIFY(QFile::remove("file-copy-destination.txt"));
1278
1279     // Fallback copy of open file.
1280     QVERIFY(file.open(QIODevice::ReadOnly));
1281     QVERIFY(file.copy("file-copy-destination.txt"));
1282     QVERIFY(QFile::exists("file-copy-destination.txt"));
1283     QVERIFY(!file.isOpen());
1284
1285     file.close(); 
1286     QFile::remove("file-copy-destination.txt");
1287 }
1288
1289 #ifdef Q_OS_WIN
1290 #include <objbase.h>
1291 #include <shlobj.h>
1292 #endif
1293
1294 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1295 static QString getWorkingDirectoryForLink(const QString &linkFileName)
1296 {
1297     bool neededCoInit = false;
1298     QString ret;
1299
1300     IShellLink *psl;
1301     HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
1302     if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
1303         neededCoInit = true;
1304         CoInitialize(NULL);
1305         hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
1306     }
1307
1308     if (SUCCEEDED(hres)) {    // Get pointer to the IPersistFile interface.
1309         IPersistFile *ppf;
1310         hres = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
1311         if (SUCCEEDED(hres))  {
1312             hres = ppf->Load((LPOLESTR)linkFileName.utf16(), STGM_READ);
1313             //The original path of the link is retrieved. If the file/folder
1314             //was moved, the return value still have the old path.
1315             if(SUCCEEDED(hres)) {
1316                 wchar_t szGotPath[MAX_PATH];
1317                 if (psl->GetWorkingDirectory(szGotPath, MAX_PATH) == NOERROR)
1318                     ret = QString::fromWCharArray(szGotPath);
1319             }
1320             ppf->Release();
1321         }
1322         psl->Release();
1323     }
1324
1325     if (neededCoInit) {
1326         CoUninitialize();
1327     }
1328
1329     return ret;
1330 }
1331 #endif
1332
1333 void tst_QFile::link()
1334 {
1335     QFile::remove("myLink.lnk");
1336
1337     QFileInfo info1(QFINDTESTDATA("tst_qfile.cpp"));
1338     QString referenceTarget = QDir::cleanPath(info1.absoluteFilePath());
1339
1340     QVERIFY(QFile::link(QFINDTESTDATA("tst_qfile.cpp"), "myLink.lnk"));
1341
1342     QFileInfo info2("myLink.lnk");
1343     QVERIFY(info2.isSymLink());
1344     QCOMPARE(info2.symLinkTarget(), referenceTarget);
1345
1346     QFile link("myLink.lnk");
1347     QVERIFY(link.open(QIODevice::ReadOnly));
1348     QCOMPARE(link.symLinkTarget(), referenceTarget);
1349     link.close();
1350
1351     QCOMPARE(QFile::symLinkTarget("myLink.lnk"), referenceTarget);
1352
1353 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1354     QString wd = getWorkingDirectoryForLink(info2.absoluteFilePath());
1355     QCOMPARE(QDir::fromNativeSeparators(wd), QDir::cleanPath(info1.absolutePath()));
1356 #endif
1357
1358     QVERIFY(QFile::remove(info2.absoluteFilePath()));
1359 }
1360
1361 void tst_QFile::linkToDir()
1362 {
1363     QFile::remove("myLinkToDir.lnk");
1364     QDir dir;
1365     dir.mkdir("myDir");
1366     QFileInfo info1("myDir");
1367     QVERIFY(QFile::link("myDir", "myLinkToDir.lnk"));
1368     QFileInfo info2("myLinkToDir.lnk");
1369 #if !(defined Q_OS_HPUX && defined(__ia64))
1370     // absurd HP-UX filesystem bug on gravlaks - checking if a symlink
1371     // resolves or not alters the file system to make the broken symlink
1372     // later fail...
1373     QVERIFY(info2.isSymLink());
1374 #endif
1375     QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath());
1376     QVERIFY(QFile::remove(info2.absoluteFilePath()));
1377     QFile::remove("myLinkToDir.lnk");
1378     dir.rmdir("myDir");
1379 }
1380
1381 void tst_QFile::absolutePathLinkToRelativePath()
1382 {
1383     QFile::remove("myDir/test.txt");
1384     QFile::remove("myDir/myLink.lnk");
1385     QDir dir;
1386     dir.mkdir("myDir");
1387     QFile("myDir/test.txt").open(QFile::WriteOnly);
1388
1389 #ifdef Q_OS_WIN
1390     QVERIFY(QFile::link("test.txt", "myDir/myLink.lnk"));
1391 #else
1392     QVERIFY(QFile::link("myDir/test.txt", "myDir/myLink.lnk"));
1393 #endif
1394     QEXPECT_FAIL("", "Symlinking using relative paths is currently different on Windows and Unix", Continue);
1395     QCOMPARE(QFileInfo(QFile(QFileInfo("myDir/myLink.lnk").absoluteFilePath()).symLinkTarget()).absoluteFilePath(),
1396              QFileInfo("myDir/test.txt").absoluteFilePath());
1397
1398     QFile::remove("myDir/test.txt");
1399     QFile::remove("myDir/myLink.lnk");
1400     dir.rmdir("myDir");
1401 }
1402
1403 void tst_QFile::readBrokenLink()
1404 {
1405     QFile::remove("myLink2.lnk");
1406     QFileInfo info1("file12");
1407     QVERIFY(QFile::link("file12", "myLink2.lnk"));
1408     QFileInfo info2("myLink2.lnk");
1409     QVERIFY(info2.isSymLink());
1410     QCOMPARE(info2.symLinkTarget(), info1.absoluteFilePath());
1411     QVERIFY(QFile::remove(info2.absoluteFilePath()));
1412     QVERIFY(QFile::link("ole/..", "myLink2.lnk"));
1413     QCOMPARE(QFileInfo("myLink2.lnk").symLinkTarget(), QDir::currentPath());
1414 }
1415
1416 void tst_QFile::readTextFile_data()
1417 {
1418     QTest::addColumn<QByteArray>("in");
1419     QTest::addColumn<QByteArray>("out");
1420
1421     QTest::newRow("empty") << QByteArray() << QByteArray();
1422     QTest::newRow("a") << QByteArray("a") << QByteArray("a");
1423     QTest::newRow("a\\rb") << QByteArray("a\rb") << QByteArray("ab");
1424     QTest::newRow("\\n") << QByteArray("\n") << QByteArray("\n");
1425     QTest::newRow("\\r\\n") << QByteArray("\r\n") << QByteArray("\n");
1426     QTest::newRow("\\r") << QByteArray("\r") << QByteArray();
1427     QTest::newRow("twolines") << QByteArray("Hello\r\nWorld\r\n") << QByteArray("Hello\nWorld\n");
1428     QTest::newRow("twolines no endline") << QByteArray("Hello\r\nWorld") << QByteArray("Hello\nWorld");
1429 }
1430
1431 void tst_QFile::readTextFile()
1432 {
1433     QFETCH(QByteArray, in);
1434     QFETCH(QByteArray, out);
1435
1436     QFile winfile("winfile.txt");
1437     QVERIFY(winfile.open(QFile::WriteOnly | QFile::Truncate));
1438     winfile.write(in);
1439     winfile.close();
1440
1441     QVERIFY(winfile.open(QFile::ReadOnly));
1442     QCOMPARE(winfile.readAll(), in);
1443     winfile.close();
1444
1445     QVERIFY(winfile.open(QFile::ReadOnly | QFile::Text));
1446     QCOMPARE(winfile.readAll(), out);
1447 }
1448
1449 void tst_QFile::readTextFile2()
1450 {
1451     {
1452         QFile file(QFINDTESTDATA("testlog.txt"));
1453         QVERIFY(file.open(QIODevice::ReadOnly));
1454         file.read(4097);
1455     }
1456
1457     {
1458         QFile file(QFINDTESTDATA("testlog.txt"));
1459         QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text));
1460         file.read(4097);
1461     }
1462 }
1463
1464 void tst_QFile::writeTextFile_data()
1465 {
1466     QTest::addColumn<QByteArray>("in");
1467
1468     QTest::newRow("empty") << QByteArray();
1469     QTest::newRow("a") << QByteArray("a");
1470     QTest::newRow("a\\rb") << QByteArray("a\rb");
1471     QTest::newRow("\\n") << QByteArray("\n");
1472     QTest::newRow("\\r\\n") << QByteArray("\r\n");
1473     QTest::newRow("\\r") << QByteArray("\r");
1474     QTest::newRow("twolines crlf") << QByteArray("Hello\r\nWorld\r\n");
1475     QTest::newRow("twolines crlf no endline") << QByteArray("Hello\r\nWorld");
1476     QTest::newRow("twolines lf") << QByteArray("Hello\nWorld\n");
1477     QTest::newRow("twolines lf no endline") << QByteArray("Hello\nWorld");
1478     QTest::newRow("mixed") << QByteArray("this\nis\r\na\nmixed\r\nfile\n");
1479 }
1480
1481 void tst_QFile::writeTextFile()
1482 {
1483     QFETCH(QByteArray, in);
1484
1485     QFile file("textfile.txt");
1486     QVERIFY(file.open(QFile::WriteOnly | QFile::Truncate | QFile::Text));
1487     QByteArray out = in;
1488 #ifdef Q_OS_WIN
1489     out.replace('\n', "\r\n");
1490 #endif
1491     QCOMPARE(file.write(in), qlonglong(in.size()));
1492     file.close();
1493
1494     file.open(QFile::ReadOnly);
1495     QCOMPARE(file.readAll(), out);
1496 }
1497
1498 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1499 void tst_QFile::largeUncFileSupport()
1500 {
1501     qint64 size = Q_INT64_C(8589934592);
1502     qint64 dataOffset = Q_INT64_C(8589914592);
1503     QByteArray knownData("LargeFile content at offset 8589914592");
1504     QString largeFile("//" + QtNetworkSettings::winServerName() + "/testsharelargefile/file.bin");
1505
1506     {
1507         // 1) Native file handling.
1508         QFile file(largeFile);
1509         QCOMPARE(file.size(), size);
1510         QVERIFY(file.open(QIODevice::ReadOnly));
1511         QCOMPARE(file.size(), size);
1512         QVERIFY(file.seek(dataOffset));
1513         QCOMPARE(file.read(knownData.size()), knownData);
1514     }
1515     {
1516         // 2) stdlib file handling.
1517         QFile file;
1518         FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb");
1519         QVERIFY(file.open(fh, QIODevice::ReadOnly));
1520         QCOMPARE(file.size(), size);
1521         QVERIFY(file.seek(dataOffset));
1522         QCOMPARE(file.read(knownData.size()), knownData);
1523         fclose(fh);
1524     }
1525     {
1526         // 3) stdio file handling.
1527         QFile file;
1528         FILE *fh = fopen(QFile::encodeName(largeFile).data(), "rb");
1529         int fd = int(_fileno(fh));
1530         QVERIFY(file.open(fd, QIODevice::ReadOnly));
1531         QCOMPARE(file.size(), size);
1532         QVERIFY(file.seek(dataOffset));
1533         QCOMPARE(file.read(knownData.size()), knownData);
1534         fclose(fh);
1535     }
1536 }
1537 #endif
1538
1539 void tst_QFile::tailFile()
1540 {
1541     QSKIP("File change notifications are so far unsupported.");
1542
1543     QFile file("tail.txt");
1544     QVERIFY(file.open(QFile::WriteOnly | QFile::Append));
1545
1546     QFile tailFile("tail.txt");
1547     QVERIFY(tailFile.open(QFile::ReadOnly));
1548     tailFile.seek(file.size());
1549
1550     QSignalSpy readSignalSpy(&tailFile, SIGNAL(readyRead()));
1551     QVERIFY(readSignalSpy.isValid());
1552
1553     file.write("", 1);
1554
1555     QTestEventLoop::instance().enterLoop(5);
1556
1557     QVERIFY(!QTestEventLoop::instance().timeout());
1558     QCOMPARE(readSignalSpy.count(), 1);
1559 }
1560
1561 void tst_QFile::flush()
1562 {
1563     QString fileName("stdfile.txt");
1564
1565     QFile::remove(fileName);
1566
1567     {
1568         QFile file(fileName);
1569         QVERIFY(file.open(QFile::WriteOnly));
1570         QCOMPARE(file.write("abc", 3),qint64(3));
1571     }
1572
1573     {
1574         QFile file(fileName);
1575         QVERIFY(file.open(QFile::WriteOnly | QFile::Append));
1576         QCOMPARE(file.pos(), qlonglong(3));
1577         QCOMPARE(file.write("def", 3), qlonglong(3));
1578         QCOMPARE(file.pos(), qlonglong(6));
1579     }
1580
1581     {
1582         QFile file("stdfile.txt");
1583         QVERIFY(file.open(QFile::ReadOnly));
1584         QCOMPARE(file.readAll(), QByteArray("abcdef"));
1585     }
1586
1587     QFile::remove(fileName);
1588 }
1589
1590 void tst_QFile::bufferedRead()
1591 {
1592     QFile::remove("stdfile.txt");
1593
1594     QFile file("stdfile.txt");
1595     QVERIFY(file.open(QFile::WriteOnly));
1596     file.write("abcdef");
1597     file.close();
1598
1599 #if defined(Q_OS_WINCE)
1600     FILE *stdFile = fopen((QCoreApplication::applicationDirPath() + "/stdfile.txt").toLatin1() , "r");
1601 #else
1602     FILE *stdFile = fopen("stdfile.txt", "r");
1603 #endif
1604     QVERIFY(stdFile);
1605     char c;
1606     QCOMPARE(int(fread(&c, 1, 1, stdFile)), 1);
1607     QCOMPARE(c, 'a');
1608     QCOMPARE(int(ftell(stdFile)), 1);
1609
1610     {
1611         QFile file;
1612         QVERIFY(file.open(stdFile, QFile::ReadOnly));
1613         QCOMPARE(file.pos(), qlonglong(1));
1614         QCOMPARE(file.read(&c, 1), qlonglong(1));
1615         QCOMPARE(c, 'b');
1616         QCOMPARE(file.pos(), qlonglong(2));
1617     }
1618
1619     fclose(stdFile);
1620 }
1621
1622 void tst_QFile::isSequential()
1623 {
1624 #ifndef Q_OS_UNIX
1625     QSKIP("Unix only test.");
1626 #endif
1627     QFile zero("/dev/null");
1628     QVERIFY(zero.open(QFile::ReadOnly));
1629     QVERIFY(zero.isSequential());
1630 }
1631
1632 void tst_QFile::encodeName()
1633 {
1634     QCOMPARE(QFile::encodeName(QString::null), QByteArray());
1635 }
1636
1637 void tst_QFile::truncate()
1638 {
1639     for (int i = 0; i < 2; ++i) {
1640         QFile file("truncate.txt");
1641         QVERIFY(file.open(QFile::WriteOnly));
1642         file.write(QByteArray(200, '@'));
1643         file.close();
1644
1645         QVERIFY(file.open((i ? QFile::WriteOnly : QFile::ReadWrite) | QFile::Truncate));
1646         file.write(QByteArray(100, '$'));
1647         file.close();
1648
1649         QVERIFY(file.open(QFile::ReadOnly));
1650         QCOMPARE(file.readAll(), QByteArray(100, '$'));
1651     }
1652 }
1653
1654 void tst_QFile::seekToPos()
1655 {
1656     {
1657         QFile file("seekToPos.txt");
1658         QVERIFY(file.open(QFile::WriteOnly));
1659         file.write("a\r\nb\r\nc\r\n");
1660         file.flush();
1661     }
1662
1663     QFile file("seekToPos.txt");
1664     QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
1665     file.seek(1);
1666     char c;
1667     QVERIFY(file.getChar(&c));
1668     QCOMPARE(c, '\n');
1669
1670     QCOMPARE(file.pos(), qint64(3));
1671     file.seek(file.pos());
1672     QCOMPARE(file.pos(), qint64(3));
1673
1674     file.seek(1);
1675     file.seek(file.pos());
1676     QCOMPARE(file.pos(), qint64(1));
1677
1678 }
1679
1680 void tst_QFile::seekAfterEndOfFile()
1681 {
1682     QLatin1String filename("seekAfterEof.dat");
1683     QFile::remove(filename);
1684     {
1685         QFile file(filename);
1686         QVERIFY(file.open(QFile::WriteOnly));
1687         file.write("abcd");
1688         QCOMPARE(file.size(), qint64(4));
1689         file.seek(8);
1690         file.write("ijkl");
1691         QCOMPARE(file.size(), qint64(12));
1692         file.seek(4);
1693         file.write("efgh");
1694         QCOMPARE(file.size(), qint64(12));
1695         file.seek(16);
1696         file.write("----");
1697         QCOMPARE(file.size(), qint64(20));
1698         file.flush();
1699     }
1700
1701     QFile file(filename);
1702     QVERIFY(file.open(QFile::ReadOnly));
1703     QByteArray contents = file.readAll();
1704     QCOMPARE(contents.left(12), QByteArray("abcdefghijkl", 12));
1705     //bytes 12-15 are uninitialised so we don't care what they read as.
1706     QCOMPARE(contents.mid(16), QByteArray("----", 4));
1707     file.close();
1708     QFile::remove(filename);
1709 }
1710
1711 void tst_QFile::FILEReadWrite()
1712 {
1713     // Tests modifying a file. First creates it then reads in 4 bytes and then overwrites these
1714     // 4 bytes with new values. At the end check to see the file contains the new values.
1715
1716     QFile::remove("FILEReadWrite.txt");
1717
1718     // create test file
1719     {
1720         QFile f("FILEReadWrite.txt");
1721         QVERIFY(f.open(QFile::WriteOnly));
1722         QDataStream ds(&f);
1723         qint8 c = 0;
1724         ds << c;
1725         c = 1;
1726         ds << c;
1727         c = 2;
1728         ds << c;
1729         c = 3;
1730         ds << c;
1731         c = 4;
1732         ds << c;
1733         c = 5;
1734         ds << c;
1735         c = 6;
1736         ds << c;
1737         c = 7;
1738         ds << c;
1739         c = 8;
1740         ds << c;
1741         c = 9;
1742         ds << c;
1743         c = 10;
1744         ds << c;
1745         c = 11;
1746         ds << c;
1747         f.close();
1748     }
1749
1750 #ifdef Q_OS_WINCE
1751     FILE *fp = fopen(qPrintable(QCoreApplication::applicationDirPath() + "\\FILEReadWrite.txt"), "r+b");
1752 #else
1753     FILE *fp = fopen("FILEReadWrite.txt", "r+b");
1754 #endif
1755     QVERIFY(fp);
1756     QFile file;
1757     QVERIFY(file.open(fp, QFile::ReadWrite));
1758     QDataStream sfile(&file) ;
1759
1760     qint8 var1,var2,var3,var4;
1761     while (!sfile.atEnd())
1762     {
1763         qint64 base = file.pos();
1764
1765         QCOMPARE(file.pos(), base + 0);
1766         sfile >> var1;
1767         QCOMPARE(file.pos(), base + 1);
1768         file.flush(); // flushing should not change the base
1769         QCOMPARE(file.pos(), base + 1);
1770         sfile >> var2;
1771         QCOMPARE(file.pos(), base + 2);
1772         sfile >> var3;
1773         QCOMPARE(file.pos(), base + 3);
1774         sfile >> var4;
1775         QCOMPARE(file.pos(), base + 4);
1776         file.seek(file.pos() - 4) ;   // Move it back 4, for we are going to write new values based on old ones
1777         QCOMPARE(file.pos(), base + 0);
1778         sfile << qint8(var1 + 5);
1779         QCOMPARE(file.pos(), base + 1);
1780         sfile << qint8(var2 + 5);
1781         QCOMPARE(file.pos(), base + 2);
1782         sfile << qint8(var3 + 5);
1783         QCOMPARE(file.pos(), base + 3);
1784         sfile << qint8(var4 + 5);
1785         QCOMPARE(file.pos(), base + 4);
1786
1787     }
1788     file.close();
1789     fclose(fp);
1790
1791     // check modified file
1792     {
1793         QFile f("FILEReadWrite.txt");
1794         QVERIFY(f.open(QFile::ReadOnly));
1795         QDataStream ds(&f);
1796         qint8 c = 0;
1797         ds >> c;
1798         QCOMPARE(c, (qint8)5);
1799         ds >> c;
1800         QCOMPARE(c, (qint8)6);
1801         ds >> c;
1802         QCOMPARE(c, (qint8)7);
1803         ds >> c;
1804         QCOMPARE(c, (qint8)8);
1805         ds >> c;
1806         QCOMPARE(c, (qint8)9);
1807         ds >> c;
1808         QCOMPARE(c, (qint8)10);
1809         ds >> c;
1810         QCOMPARE(c, (qint8)11);
1811         ds >> c;
1812         QCOMPARE(c, (qint8)12);
1813         ds >> c;
1814         QCOMPARE(c, (qint8)13);
1815         ds >> c;
1816         QCOMPARE(c, (qint8)14);
1817         ds >> c;
1818         QCOMPARE(c, (qint8)15);
1819         ds >> c;
1820         QCOMPARE(c, (qint8)16);
1821         f.close();
1822     }
1823
1824     QFile::remove("FILEReadWrite.txt");
1825 }
1826
1827
1828 /*
1829 #include <qglobal.h>
1830 #define BUFFSIZE 1
1831 #define FILESIZE   0x10000000f
1832 void tst_QFile::largeFileSupport()
1833 {
1834 #ifdef Q_OS_SOLARIS
1835     QSKIP("Solaris does not support statfs");
1836 #else
1837     qlonglong sizeNeeded = 2147483647;
1838     sizeNeeded *= 2;
1839     sizeNeeded += 1024;
1840     qlonglong freespace = qlonglong(0);
1841 #ifdef Q_OS_WIN
1842     _ULARGE_INTEGER free;
1843     if (::GetDiskFreeSpaceEx((wchar_t*)QDir::currentPath().utf16(), &free, 0, 0))
1844         freespace = free.QuadPart;
1845     if (freespace != 0) {
1846 #elif defined(Q_OS_IRIX)
1847     struct statfs info;
1848     if (statfs(QDir::currentPath().local8Bit(), &info, sizeof(struct statfs), 0) == 0) {
1849         freespace = qlonglong(info.f_bfree * info.f_bsize);
1850 #else
1851     struct statfs info;
1852     if (statfs(const_cast<char *>(QDir::currentPath().toLocal8Bit().constData()), &info) == 0) {
1853         freespace = qlonglong(info.f_bavail * info.f_bsize);
1854 #endif
1855         if (freespace > sizeNeeded) {
1856             QFile bigFile("bigfile");
1857             if (bigFile.open(QFile::ReadWrite)) {
1858                 char c[BUFFSIZE] = {'a'};
1859                 QVERIFY(bigFile.write(c, BUFFSIZE) == BUFFSIZE);
1860                 qlonglong oldPos = bigFile.pos();
1861                 QVERIFY(bigFile.resize(sizeNeeded));
1862                 QCOMPARE(oldPos, bigFile.pos());
1863                 QVERIFY(bigFile.seek(sizeNeeded - BUFFSIZE));
1864                 QVERIFY(bigFile.write(c, BUFFSIZE) == BUFFSIZE);
1865
1866                 bigFile.close();
1867                 if (bigFile.open(QFile::ReadOnly)) {
1868                     QVERIFY(bigFile.read(c, BUFFSIZE) == BUFFSIZE);
1869                     int i = 0;
1870                     for (i=0; i<BUFFSIZE; i++)
1871                         QCOMPARE(c[i], 'a');
1872                     QVERIFY(bigFile.seek(sizeNeeded - BUFFSIZE));
1873                     QVERIFY(bigFile.read(c, BUFFSIZE) == BUFFSIZE);
1874                     for (i=0; i<BUFFSIZE; i++)
1875                         QCOMPARE(c[i], 'a');
1876                     bigFile.close();
1877                     QVERIFY(bigFile.remove());
1878                 } else {
1879                     QVERIFY(bigFile.remove());
1880                     QFAIL("Could not reopen file");
1881                 }
1882             } else {
1883                 QFAIL("Could not open file");
1884             }
1885         } else {
1886             QSKIP("Not enough space to run test");
1887         }
1888     } else {
1889         QFAIL("Could not determin disk space");
1890     }
1891 #endif
1892 }
1893 */
1894
1895 void tst_QFile::i18nFileName_data()
1896 {
1897     QTest::addColumn<QString>("fileName");
1898
1899     QTest::newRow( "01" ) << QString::fromUtf8("xxxxxxx.txt");
1900 }
1901
1902 void tst_QFile::i18nFileName()
1903 {
1904      QFETCH(QString, fileName);
1905      if (QFile::exists(fileName)) {
1906          QVERIFY(QFile::remove(fileName));
1907      }
1908      {
1909         QFile file(fileName);
1910         QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
1911         QTextStream ts(&file);
1912         ts.setCodec("UTF-8");
1913         ts << fileName << endl;
1914      }
1915      {
1916         QFile file(fileName);
1917         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
1918         QTextStream ts(&file);
1919         ts.setCodec("UTF-8");
1920         QString line = ts.readLine();
1921         QCOMPARE(line, fileName);
1922      }
1923      QVERIFY(QFile::remove(fileName));
1924 }
1925
1926
1927 void tst_QFile::longFileName_data()
1928 {
1929     QTest::addColumn<QString>("fileName");
1930
1931     QTest::newRow( "16 chars" ) << QString::fromLatin1("longFileName.txt");
1932     QTest::newRow( "52 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName.txt");
1933     QTest::newRow( "148 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
1934                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1935                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt");
1936     QTest::newRow( "244 chars" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
1937                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1938                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1939                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1940                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt");
1941     QTest::newRow( "244 chars to absolutepath" ) << QFileInfo(QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
1942                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1943                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1944                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1945                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt")).absoluteFilePath();
1946   /* needs to be put on a windows 2000 > test machine
1947   QTest::newRow( "244 chars on UNC" ) <<  QString::fromLatin1("//arsia/D/troll/tmp/longFileNamelongFileNamelongFileNamelongFileName"
1948                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1949                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1950                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1951                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt");*/
1952 }
1953
1954 void tst_QFile::longFileName()
1955 {
1956     QFETCH(QString, fileName);
1957     if (QFile::exists(fileName)) {
1958         QVERIFY(QFile::remove(fileName));
1959     }
1960     {
1961         QFile file(fileName);
1962 #if defined(Q_OS_WINCE)
1963         QEXPECT_FAIL("244 chars", "Full pathname must be less than 260 chars", Abort);
1964         QEXPECT_FAIL("244 chars to absolutepath", "Full pathname must be less than 260 chars", Abort);
1965 #endif
1966         QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
1967         QTextStream ts(&file);
1968         ts << fileName << endl;
1969     }
1970     {
1971         QFile file(fileName);
1972         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
1973         QTextStream ts(&file);
1974         QString line = ts.readLine();
1975         QCOMPARE(line, fileName);
1976     }
1977     QString newName = fileName + QLatin1String("1");
1978     {
1979         QVERIFY(QFile::copy(fileName, newName));
1980         QFile file(newName);
1981         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
1982         QTextStream ts(&file);
1983         QString line = ts.readLine();
1984         QCOMPARE(line, fileName);
1985
1986     }
1987     QVERIFY(QFile::remove(newName));
1988     {
1989         QVERIFY(QFile::rename(fileName, newName));
1990         QFile file(newName);
1991         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
1992         QTextStream ts(&file);
1993         QString line = ts.readLine();
1994         QCOMPARE(line, fileName);
1995     }
1996     QVERIFY(QFile::exists(newName));
1997     QVERIFY(QFile::remove(newName));
1998 }
1999
2000 #ifdef QT_BUILD_INTERNAL
2001 class MyEngine : public QAbstractFileEngine
2002 {
2003 public:
2004     MyEngine(int n) { number = n; }
2005     virtual ~MyEngine() {}
2006
2007     void setFileName(const QString &) {}
2008     bool open(QIODevice::OpenMode) { return false; }
2009     bool close() { return false; }
2010     bool flush() { return false; }
2011     qint64 size() const { return 123 + number; }
2012     qint64 at() const { return -1; }
2013     bool seek(qint64) { return false; }
2014     bool isSequential() const { return false; }
2015     qint64 read(char *, qint64) { return -1; }
2016     qint64 write(const char *, qint64) { return -1; }
2017     bool remove() { return false; }
2018     bool copy(const QString &) { return false; }
2019     bool rename(const QString &) { return false; }
2020     bool link(const QString &) { return false; }
2021     bool mkdir(const QString &, bool) const { return false; }
2022     bool rmdir(const QString &, bool) const { return false; }
2023     bool setSize(qint64) { return false; }
2024     QStringList entryList(QDir::Filters, const QStringList &) const { return QStringList(); }
2025     bool caseSensitive() const { return false; }
2026     bool isRelativePath() const { return false; }
2027     FileFlags fileFlags(FileFlags) const { return 0; }
2028     bool chmod(uint) { return false; }
2029     QString fileName(FileName) const { return name; }
2030     uint ownerId(FileOwner) const { return 0; }
2031     QString owner(FileOwner) const { return QString(); }
2032     QDateTime fileTime(FileTime) const { return QDateTime(); }
2033
2034 private:
2035     int number;
2036     QString name;
2037 };
2038
2039 class MyHandler : public QAbstractFileEngineHandler
2040 {
2041 public:
2042     inline QAbstractFileEngine *create(const QString &) const
2043     {
2044         return new MyEngine(1);
2045     }
2046 };
2047
2048 class MyHandler2 : public QAbstractFileEngineHandler
2049 {
2050 public:
2051     inline QAbstractFileEngine *create(const QString &) const
2052     {
2053         return new MyEngine(2);
2054     }
2055 };
2056 #endif
2057
2058 void tst_QFile::fileEngineHandler()
2059 {
2060     // A file that does not exist has a size of 0.
2061     QFile::remove("ole.bull");
2062     QFile file("ole.bull");
2063     QCOMPARE(file.size(), qint64(0));
2064
2065 #ifdef QT_BUILD_INTERNAL
2066     // Instantiating our handler will enable the new engine.
2067     MyHandler handler;
2068     file.setFileName("ole.bull");
2069     QCOMPARE(file.size(), qint64(124));
2070
2071     // A new, identical handler should take preference over the last one.
2072     MyHandler2 handler2;
2073     file.setFileName("ole.bull");
2074     QCOMPARE(file.size(), qint64(125));
2075 #endif
2076 }
2077
2078 #ifdef QT_BUILD_INTERNAL
2079 class MyRecursiveHandler : public QAbstractFileEngineHandler
2080 {
2081 public:
2082     inline QAbstractFileEngine *create(const QString &fileName) const
2083     {
2084         if (fileName.startsWith(":!")) {
2085             QDir dir;
2086             QString realFile = QFINDTESTDATA(fileName.mid(2));
2087             if (dir.exists(realFile))
2088                 return new QFSFileEngine(realFile);
2089         }
2090         return 0;
2091     }
2092 };
2093 #endif
2094
2095 #ifdef QT_BUILD_INTERNAL
2096 void tst_QFile::useQFileInAFileHandler()
2097 {
2098     // This test should not dead-lock
2099     MyRecursiveHandler handler;
2100     QFile file(":!tst_qfile.cpp");
2101     QVERIFY(file.exists());
2102 }
2103 #endif
2104
2105 void tst_QFile::getCharFF()
2106 {
2107     QFile file("file.txt");
2108     file.open(QFile::ReadWrite);
2109     file.write("\xff\xff\xff");
2110     file.flush();
2111     file.seek(0);
2112
2113     char c;
2114     QVERIFY(file.getChar(&c));
2115     QVERIFY(file.getChar(&c));
2116     QVERIFY(file.getChar(&c));
2117 }
2118
2119 void tst_QFile::remove_and_exists()
2120 {
2121     QFile::remove("tull_i_grunn.txt");
2122     QFile f("tull_i_grunn.txt");
2123
2124     QVERIFY(!f.exists());
2125
2126     bool opened = f.open(QIODevice::WriteOnly);
2127     QVERIFY(opened);
2128
2129     f.write(QString("testing that remove/exists work...").toLatin1());
2130     f.close();
2131
2132     QVERIFY(f.exists());
2133
2134     f.remove();
2135     QVERIFY(!f.exists());
2136 }
2137
2138 void tst_QFile::removeOpenFile()
2139 {
2140     {
2141         // remove an opened, write-only file
2142         QFile::remove("remove_unclosed.txt");
2143         QFile f("remove_unclosed.txt");
2144
2145         QVERIFY(!f.exists());
2146         bool opened = f.open(QIODevice::WriteOnly);
2147         QVERIFY(opened);
2148         f.write(QString("testing that remove closes the file first...").toLatin1());
2149
2150         bool removed = f.remove(); // remove should both close and remove the file
2151         QVERIFY(removed);
2152         QVERIFY(!f.isOpen());
2153         QVERIFY(!f.exists());
2154         QVERIFY(f.error() == QFile::NoError);
2155     }
2156
2157     {
2158         // remove an opened, read-only file
2159         QFile::remove("remove_unclosed.txt");
2160
2161         // first, write a file that we can remove
2162         {
2163             QFile f("remove_unclosed.txt");
2164             QVERIFY(!f.exists());
2165             bool opened = f.open(QIODevice::WriteOnly);
2166             QVERIFY(opened);
2167             f.write(QString("testing that remove closes the file first...").toLatin1());
2168             f.close();
2169         }
2170
2171         QFile f("remove_unclosed.txt");
2172         bool opened = f.open(QIODevice::ReadOnly);
2173         QVERIFY(opened);
2174         f.readAll();
2175         // this used to only fail on FreeBSD (and Mac OS X)
2176         QVERIFY(f.flush());
2177         bool removed = f.remove(); // remove should both close and remove the file
2178         QVERIFY(removed);
2179         QVERIFY(!f.isOpen());
2180         QVERIFY(!f.exists());
2181         QVERIFY(f.error() == QFile::NoError);
2182     }
2183 }
2184
2185 void tst_QFile::fullDisk()
2186 {
2187     QFile file("/dev/full");
2188     if (!file.exists())
2189         QSKIP("/dev/full doesn't exist on this system");
2190
2191     QVERIFY(file.open(QIODevice::WriteOnly));
2192     file.write("foobar", 6);
2193
2194     QVERIFY(!file.flush());
2195     QCOMPARE(file.error(), QFile::ResourceError);
2196     QVERIFY(!file.flush());
2197     QCOMPARE(file.error(), QFile::ResourceError);
2198
2199     char c = 0;
2200     file.write(&c, 0);
2201     QVERIFY(!file.flush());
2202     QCOMPARE(file.error(), QFile::ResourceError);
2203     QCOMPARE(file.write(&c, 1), qint64(1));
2204     QVERIFY(!file.flush());
2205     QCOMPARE(file.error(), QFile::ResourceError);
2206
2207     file.close();
2208     QVERIFY(!file.isOpen());
2209     QCOMPARE(file.error(), QFile::ResourceError);
2210
2211     file.open(QIODevice::WriteOnly);
2212     QCOMPARE(file.error(), QFile::NoError);
2213     QVERIFY(file.flush()); // Shouldn't inherit write buffer
2214     file.close();
2215     QCOMPARE(file.error(), QFile::NoError);
2216
2217     // try again without flush:
2218     QVERIFY(file.open(QIODevice::WriteOnly));
2219     file.write("foobar", 6);
2220     file.close();
2221     QVERIFY(file.error() != QFile::NoError);
2222 }
2223
2224 void tst_QFile::writeLargeDataBlock_data()
2225 {
2226     QTest::addColumn<QString>("fileName");
2227     QTest::addColumn<int>("type");
2228
2229     QTest::newRow("localfile-QFile")  << "./largeblockfile.txt" << (int)OpenQFile;
2230     QTest::newRow("localfile-Fd")     << "./largeblockfile.txt" << (int)OpenFd;
2231     QTest::newRow("localfile-Stream") << "./largeblockfile.txt" << (int)OpenStream;
2232
2233 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
2234     // Some semi-randomness to avoid collisions.
2235     QTest::newRow("unc file")
2236         << QString("//" + QtNetworkSettings::winServerName() + "/TESTSHAREWRITABLE/largefile-%1-%2.txt")
2237         .arg(QHostInfo::localHostName())
2238         .arg(QTime::currentTime().msec()) << (int)OpenQFile;
2239 #endif
2240 }
2241
2242 static QByteArray getLargeDataBlock()
2243 {
2244     static QByteArray array;
2245
2246     if (array.isNull())
2247     {
2248 #if defined(Q_OS_WINCE)
2249         int resizeSize = 1024 * 1024; // WinCE does not have much space
2250 #else
2251         int resizeSize = 64 * 1024 * 1024;
2252 #endif
2253         array.resize(resizeSize);
2254         for (int i = 0; i < array.size(); ++i)
2255             array[i] = uchar(i);
2256     }
2257
2258     return array;
2259 }
2260
2261 void tst_QFile::writeLargeDataBlock()
2262 {
2263     QFETCH(QString, fileName);
2264     QFETCH( int, type );
2265
2266     QByteArray const originalData = getLargeDataBlock();
2267
2268     {
2269         QFile file(fileName);
2270
2271         QVERIFY2( openFile(file, QIODevice::WriteOnly, (FileType)type),
2272             qPrintable(QString("Couldn't open file for writing: [%1]").arg(fileName)) );
2273         qint64 fileWriteOriginalData = file.write(originalData);
2274         qint64 originalDataSize      = (qint64)originalData.size();
2275 #if defined(Q_OS_WIN)
2276         if (fileWriteOriginalData != originalDataSize) {
2277             qWarning() << qPrintable(QString("Error writing a large data block to [%1]: %2")
2278                 .arg(fileName)
2279                 .arg(file.errorString()));
2280             QEXPECT_FAIL("unc file", "QTBUG-26906", Abort);
2281         }
2282 #endif
2283         QCOMPARE( fileWriteOriginalData, originalDataSize );
2284         QVERIFY( file.flush() );
2285
2286         closeFile(file);
2287     }
2288
2289     QByteArray readData;
2290
2291     {
2292         QFile file(fileName);
2293
2294         QVERIFY2( openFile(file, QIODevice::ReadOnly, (FileType)type),
2295             qPrintable(QString("Couldn't open file for reading: [%1]").arg(fileName)) );
2296         readData = file.readAll();
2297         closeFile(file);
2298     }
2299
2300     QCOMPARE( readData, originalData );
2301     QVERIFY( QFile::remove(fileName) );
2302 }
2303
2304 void tst_QFile::readFromWriteOnlyFile()
2305 {
2306     QFile file("writeonlyfile");
2307     QVERIFY(file.open(QFile::WriteOnly));
2308     char c;
2309     QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device");
2310     QCOMPARE(file.read(&c, 1), qint64(-1));
2311 }
2312
2313 void tst_QFile::writeToReadOnlyFile()
2314 {
2315     QFile file("readonlyfile");
2316     QVERIFY(file.open(QFile::ReadOnly));
2317     char c = 0;
2318     QTest::ignoreMessage(QtWarningMsg, "QIODevice::write: ReadOnly device");
2319     QCOMPARE(file.write(&c, 1), qint64(-1));
2320 }
2321
2322 void tst_QFile::virtualFile()
2323 {
2324     // test if QFile works with virtual files
2325     QString fname;
2326 #if defined(Q_OS_LINUX)
2327     fname = "/proc/self/maps";
2328 #elif defined(Q_OS_AIX)
2329     fname = QString("/proc/%1/map").arg(getpid());
2330 #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
2331     fname = "/proc/curproc/map";
2332 #else
2333     QSKIP("This platform does not have 0-sized virtual files");
2334 #endif
2335
2336     // consistency check
2337     QFileInfo fi(fname);
2338     QVERIFY(fi.exists());
2339     QVERIFY(fi.isFile());
2340     QCOMPARE(fi.size(), Q_INT64_C(0));
2341
2342     // open the file
2343     QFile f(fname);
2344     QVERIFY(f.open(QIODevice::ReadOnly));
2345     QCOMPARE(f.size(), Q_INT64_C(0));
2346     QVERIFY(f.atEnd());
2347
2348     // read data
2349     QByteArray data = f.read(16);
2350     QCOMPARE(data.size(), 16);
2351     QCOMPARE(f.pos(), Q_INT64_C(16));
2352
2353     // line-reading
2354     data = f.readLine();
2355     QVERIFY(!data.isEmpty());
2356
2357     // read all:
2358     data = f.readAll();
2359     QVERIFY(f.pos() != 0);
2360     QVERIFY(!data.isEmpty());
2361
2362     // seeking
2363     QVERIFY(f.seek(1));
2364     QCOMPARE(f.pos(), Q_INT64_C(1));
2365 }
2366
2367 void tst_QFile::textFile()
2368 {
2369 #if defined(Q_OS_WINCE)
2370     FILE *fs = ::fopen((QCoreApplication::applicationDirPath() + "/writeabletextfile").toLatin1() , "wt");
2371 #elif defined(Q_OS_WIN)
2372     FILE *fs = ::fopen("writeabletextfile", "wt");
2373 #else
2374     FILE *fs = ::fopen("writeabletextfile", "w");
2375 #endif
2376     QFile f;
2377     QByteArray part1("This\nis\na\nfile\nwith\nnewlines\n");
2378     QByteArray part2("Add\nsome\nmore\nnewlines\n");
2379
2380     QVERIFY(f.open(fs, QIODevice::WriteOnly));
2381     f.write(part1);
2382     f.write(part2);
2383     f.close();
2384     ::fclose(fs);
2385
2386     QFile file("writeabletextfile");
2387     QVERIFY(file.open(QIODevice::ReadOnly));
2388
2389     QByteArray data = file.readAll();
2390
2391     QByteArray expected = part1 + part2;
2392 #ifdef Q_OS_WIN
2393     expected.replace("\n", "\015\012");
2394 #endif
2395     QCOMPARE(data, expected);
2396     file.close();
2397     file.remove();
2398 }
2399
2400 void tst_QFile::rename_data()
2401 {
2402     QTest::addColumn<QString>("source");
2403     QTest::addColumn<QString>("destination");
2404     QTest::addColumn<bool>("result");
2405
2406     QTest::newRow("a -> b") << QString("a") << QString("b") << false;
2407     QTest::newRow("a -> .") << QString("a") << QString(".") << false;
2408     QTest::newRow("renamefile -> renamefile") << QString("renamefile") << QString("renamefile") << false;
2409     QTest::newRow("renamefile -> noreadfile") << QString("renamefile") << QString("noreadfile") << false;
2410 #if defined(Q_OS_UNIX)
2411     QTest::newRow("renamefile -> /etc/renamefile") << QString("renamefile") << QString("/etc/renamefile") << false;
2412 #endif
2413     QTest::newRow("renamefile -> renamedfile") << QString("renamefile") << QString("renamedfile") << true;
2414     QTest::newRow("renamefile -> ..") << QString("renamefile") << QString("..") << false;
2415 }
2416
2417 void tst_QFile::rename()
2418 {
2419     QFETCH(QString, source);
2420     QFETCH(QString, destination);
2421     QFETCH(bool, result);
2422
2423 #if defined(Q_OS_UNIX)
2424     if (strcmp(QTest::currentDataTag(), "renamefile -> /etc/renamefile") == 0) {
2425         if (::getuid() == 0)
2426             QSKIP("Running this test as root doesn't make sense");
2427     }
2428 #endif
2429
2430     QFile::remove("renamedfile");
2431     QFile f("renamefile");
2432     f.open(QFile::WriteOnly);
2433     f.close();
2434
2435     QFile file(source);
2436     QCOMPARE(file.rename(destination), result);
2437
2438     if (result)
2439         QCOMPARE(file.error(), QFile::NoError);
2440     else
2441         QCOMPARE(file.error(), QFile::RenameError);
2442
2443     QFile::remove("renamefile");
2444 }
2445
2446 /*!
2447  \since 4.5
2448
2449  Some special files have QFile::atEnd() returning true, even though there is
2450  more data available. True for corner cases, as well as some mounts on OS X.
2451
2452  Here, we reproduce that condition by having a QFile sub-class with this
2453  peculiar atEnd() behavior.
2454 */
2455 void tst_QFile::renameWithAtEndSpecialFile() const
2456 {
2457     class PeculiarAtEnd : public QFile
2458     {
2459     public:
2460         virtual bool atEnd() const
2461         {
2462             return true;
2463         }
2464     };
2465
2466     const QString newName(QLatin1String("newName.txt"));
2467     /* Cleanup, so we're a bit more robust. */
2468     QFile::remove(newName);
2469
2470     const QString originalName(QString(QFINDTESTDATA("forRenaming.txt")));
2471
2472     PeculiarAtEnd file;
2473     file.setFileName(originalName);
2474     QVERIFY(file.open(QIODevice::ReadOnly));
2475
2476     QVERIFY(file.rename(newName));
2477
2478     file.close();
2479     /* Guess what, we have to rename it back, otherwise we'll fail on second
2480      * invocation. */
2481     QVERIFY(QFile::rename(newName, originalName));
2482 }
2483
2484 void tst_QFile::renameFallback()
2485 {
2486     // Using a resource file both to trigger QFile::rename's fallback handling
2487     // and as a *read-only* source whose move should fail.
2488     QFile file(":/rename-fallback.qrc");
2489     QVERIFY(file.exists() && "(test-precondition)");
2490     QFile::remove("file-rename-destination.txt");
2491
2492     QVERIFY(!file.rename("file-rename-destination.txt"));
2493     QVERIFY(!QFile::exists("file-rename-destination.txt"));
2494     QVERIFY(!file.isOpen());
2495 }
2496
2497 void tst_QFile::renameMultiple()
2498 {
2499     // create the file if it doesn't exist
2500     QFile file("file-to-be-renamed.txt");
2501     QFile file2("existing-file.txt");
2502     QVERIFY(file.open(QIODevice::ReadWrite) && "(test-precondition)");
2503     QVERIFY(file2.open(QIODevice::ReadWrite) && "(test-precondition)");
2504
2505     // any stale files from previous test failures?
2506     QFile::remove("file-renamed-once.txt");
2507     QFile::remove("file-renamed-twice.txt");
2508
2509     // begin testing
2510     QVERIFY(QFile::exists("existing-file.txt"));
2511     QVERIFY(!file.rename("existing-file.txt"));
2512     QCOMPARE(file.error(), QFile::RenameError);
2513     QCOMPARE(file.fileName(), QString("file-to-be-renamed.txt"));
2514
2515     QVERIFY(file.rename("file-renamed-once.txt"));
2516     QVERIFY(!file.isOpen());
2517     QCOMPARE(file.fileName(), QString("file-renamed-once.txt"));
2518
2519     QVERIFY(QFile::exists("existing-file.txt"));
2520     QVERIFY(!file.rename("existing-file.txt"));
2521     QCOMPARE(file.error(), QFile::RenameError);
2522     QCOMPARE(file.fileName(), QString("file-renamed-once.txt"));
2523
2524     QVERIFY(file.rename("file-renamed-twice.txt"));
2525     QVERIFY(!file.isOpen());
2526     QCOMPARE(file.fileName(), QString("file-renamed-twice.txt"));
2527
2528     QVERIFY(QFile::exists("existing-file.txt"));
2529     QVERIFY(!QFile::exists("file-to-be-renamed.txt"));
2530     QVERIFY(!QFile::exists("file-renamed-once.txt"));
2531     QVERIFY(QFile::exists("file-renamed-twice.txt"));
2532
2533     file.remove();
2534     file2.remove();
2535     QVERIFY(!QFile::exists("file-renamed-twice.txt"));
2536     QVERIFY(!QFile::exists("existing-file.txt"));
2537 }
2538
2539 void tst_QFile::appendAndRead()
2540 {
2541     QFile writeFile(QLatin1String("appendfile.txt"));
2542     QVERIFY(writeFile.open(QIODevice::WriteOnly | QIODevice::Truncate));
2543
2544     QFile readFile(QLatin1String("appendfile.txt"));
2545     QVERIFY(readFile.open(QIODevice::ReadOnly));
2546
2547     // Write to the end of the file, then read that character back, and so on.
2548     for (int i = 0; i < 100; ++i) {
2549         char c = '\0';
2550         writeFile.putChar(char(i % 256));
2551         writeFile.flush();
2552         QVERIFY(readFile.getChar(&c));
2553         QCOMPARE(c, char(i % 256));
2554         QCOMPARE(readFile.pos(), writeFile.pos());
2555     }
2556
2557     // Write blocks and read them back
2558     for (int j = 0; j < 18; ++j) {
2559         writeFile.write(QByteArray(1 << j, '@'));
2560         writeFile.flush();
2561         QCOMPARE(readFile.read(1 << j).size(), 1 << j);
2562     }
2563
2564     readFile.close();
2565     QFile::remove(QLatin1String("appendfile.txt"));
2566 }
2567
2568 void tst_QFile::miscWithUncPathAsCurrentDir()
2569 {
2570 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
2571     QString current = QDir::currentPath();
2572     QVERIFY(QDir::setCurrent("//" + QtNetworkSettings::winServerName() + "/testshare"));
2573     QFile file("test.pri");
2574     QVERIFY(file.exists());
2575     QCOMPARE(int(file.size()), 34);
2576     QVERIFY(file.open(QIODevice::ReadOnly));
2577     QVERIFY(QDir::setCurrent(current));
2578 #endif
2579 }
2580
2581 void tst_QFile::standarderror()
2582 {
2583     QFile f;
2584     bool ok = f.open(stderr, QFile::WriteOnly);
2585     QVERIFY(ok);
2586     f.close();
2587 }
2588
2589 void tst_QFile::handle()
2590 {
2591     int fd;
2592 #if !defined(Q_OS_WINCE)
2593     QFile file(QFINDTESTDATA("tst_qfile.cpp"));
2594     QVERIFY(file.open(QIODevice::ReadOnly));
2595     fd = int(file.handle());
2596     QVERIFY(fd > 2);
2597     QCOMPARE(int(file.handle()), fd);
2598     char c = '\0';
2599     QT_READ(int(file.handle()), &c, 1);
2600     QCOMPARE(c, '/');
2601
2602     // test if the QFile and the handle remain in sync
2603     QVERIFY(file.getChar(&c));
2604     QCOMPARE(c, '*');
2605
2606     // same, but read from QFile first now
2607     file.close();
2608     QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered));
2609     fd = int(file.handle());
2610     QVERIFY(fd > 2);
2611     QVERIFY(file.getChar(&c));
2612     QCOMPARE(c, '/');
2613 #ifdef Q_OS_UNIX
2614     QCOMPARE(QT_READ(fd, &c, 1), ssize_t(1));
2615 #else
2616     QCOMPARE(QT_READ(fd, &c, 1), 1);
2617 #endif
2618
2619     QCOMPARE(c, '*');
2620 #endif
2621
2622     //test round trip of adopted stdio file handle
2623     QFile file2;
2624     FILE *fp = fopen(qPrintable(QFINDTESTDATA("tst_qfile.cpp")), "r");
2625     file2.open(fp, QIODevice::ReadOnly);
2626     QCOMPARE(int(file2.handle()), int(fileno(fp)));
2627     QCOMPARE(int(file2.handle()), int(fileno(fp)));
2628     fclose(fp);
2629
2630     //test round trip of adopted posix file handle
2631 #ifdef Q_OS_UNIX
2632     QFile file3;
2633     fd = QT_OPEN(qPrintable(QFINDTESTDATA("tst_qfile.cpp")), QT_OPEN_RDONLY);
2634     file3.open(fd, QIODevice::ReadOnly);
2635     QCOMPARE(int(file3.handle()), fd);
2636     QT_CLOSE(fd);
2637 #endif
2638 }
2639
2640 void tst_QFile::nativeHandleLeaks()
2641 {
2642     int fd1, fd2;
2643
2644 #ifdef Q_OS_WIN
2645     HANDLE handle1, handle2;
2646 #endif
2647
2648     {
2649         QFile file("qt_file.tmp");
2650         QVERIFY( file.open(QIODevice::ReadWrite) );
2651
2652         fd1 = file.handle();
2653         QVERIFY( -1 != fd1 );
2654     }
2655
2656 #ifdef Q_OS_WIN
2657     handle1 = ::CreateFileA("qt_file.tmp", GENERIC_READ, 0, NULL,
2658             OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2659     QVERIFY( INVALID_HANDLE_VALUE != handle1 );
2660     QVERIFY( ::CloseHandle(handle1) );
2661 #endif
2662
2663     {
2664         QFile file("qt_file.tmp");
2665         QVERIFY( file.open(QIODevice::ReadOnly) );
2666
2667         fd2 = file.handle();
2668         QVERIFY( -1 != fd2 );
2669     }
2670
2671 #ifdef Q_OS_WIN
2672     handle2 = ::CreateFileA("qt_file.tmp", GENERIC_READ, 0, NULL,
2673             OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2674     QVERIFY( INVALID_HANDLE_VALUE != handle2 );
2675     QVERIFY( ::CloseHandle(handle2) );
2676 #endif
2677
2678     QCOMPARE( fd2, fd1 );
2679
2680 #ifdef Q_OS_WIN
2681     QCOMPARE( handle2, handle1 );
2682 #endif
2683 }
2684
2685 void tst_QFile::readEof_data()
2686 {
2687     QTest::addColumn<QString>("filename");
2688     QTest::addColumn<int>("imode");
2689
2690     QTest::newRow("buffered") << QFINDTESTDATA("testfile.txt") << 0;
2691     QTest::newRow("unbuffered") << QFINDTESTDATA("testfile.txt") << int(QIODevice::Unbuffered);
2692
2693 #if defined(Q_OS_UNIX)
2694     QTest::newRow("sequential,buffered") << "/dev/null" << 0;
2695     QTest::newRow("sequential,unbuffered") << "/dev/null" << int(QIODevice::Unbuffered);
2696 #endif
2697 }
2698
2699 void tst_QFile::readEof()
2700 {
2701     QFETCH(QString, filename);
2702     QFETCH(int, imode);
2703     QIODevice::OpenMode mode = QIODevice::OpenMode(imode);
2704
2705     {
2706         QFile file(filename);
2707         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2708         bool isSequential = file.isSequential();
2709         if (!isSequential) {
2710             QVERIFY(file.seek(245));
2711             QVERIFY(file.atEnd());
2712         }
2713
2714         char buf[10];
2715         int ret = file.read(buf, sizeof buf);
2716         QCOMPARE(ret, 0);
2717         QVERIFY(file.error() == QFile::NoError);
2718         QVERIFY(file.atEnd());
2719
2720         // Do it again to ensure that we get the same result
2721         ret = file.read(buf, sizeof buf);
2722         QCOMPARE(ret, 0);
2723         QVERIFY(file.error() == QFile::NoError);
2724         QVERIFY(file.atEnd());
2725     }
2726
2727     {
2728         QFile file(filename);
2729         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2730         bool isSequential = file.isSequential();
2731         if (!isSequential) {
2732             QVERIFY(file.seek(245));
2733             QVERIFY(file.atEnd());
2734         }
2735
2736         QByteArray ret = file.read(10);
2737         QVERIFY(ret.isEmpty());
2738         QVERIFY(file.error() == QFile::NoError);
2739         QVERIFY(file.atEnd());
2740
2741         // Do it again to ensure that we get the same result
2742         ret = file.read(10);
2743         QVERIFY(ret.isEmpty());
2744         QVERIFY(file.error() == QFile::NoError);
2745         QVERIFY(file.atEnd());
2746     }
2747
2748     {
2749         QFile file(filename);
2750         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2751         bool isSequential = file.isSequential();
2752         if (!isSequential) {
2753             QVERIFY(file.seek(245));
2754             QVERIFY(file.atEnd());
2755         }
2756
2757         char buf[10];
2758         int ret = file.readLine(buf, sizeof buf);
2759         QCOMPARE(ret, -1);
2760         QVERIFY(file.error() == QFile::NoError);
2761         QVERIFY(file.atEnd());
2762
2763         // Do it again to ensure that we get the same result
2764         ret = file.readLine(buf, sizeof buf);
2765         QCOMPARE(ret, -1);
2766         QVERIFY(file.error() == QFile::NoError);
2767         QVERIFY(file.atEnd());
2768     }
2769
2770     {
2771         QFile file(filename);
2772         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2773         bool isSequential = file.isSequential();
2774         if (!isSequential) {
2775             QVERIFY(file.seek(245));
2776             QVERIFY(file.atEnd());
2777         }
2778
2779         QByteArray ret = file.readLine();
2780         QVERIFY(ret.isNull());
2781         QVERIFY(file.error() == QFile::NoError);
2782         QVERIFY(file.atEnd());
2783
2784         // Do it again to ensure that we get the same result
2785         ret = file.readLine();
2786         QVERIFY(ret.isNull());
2787         QVERIFY(file.error() == QFile::NoError);
2788         QVERIFY(file.atEnd());
2789     }
2790
2791     {
2792         QFile file(filename);
2793         QVERIFY(file.open(QIODevice::ReadOnly | mode));
2794         bool isSequential = file.isSequential();
2795         if (!isSequential) {
2796             QVERIFY(file.seek(245));
2797             QVERIFY(file.atEnd());
2798         }
2799
2800         char c;
2801         QVERIFY(!file.getChar(&c));
2802         QVERIFY(file.error() == QFile::NoError);
2803         QVERIFY(file.atEnd());
2804
2805         // Do it again to ensure that we get the same result
2806         QVERIFY(!file.getChar(&c));
2807         QVERIFY(file.error() == QFile::NoError);
2808         QVERIFY(file.atEnd());
2809     }
2810 }
2811
2812 void tst_QFile::posAfterFailedStat()
2813 {
2814     // Regression test for a bug introduced in 4.3.0; after a failed stat,
2815     // pos() could no longer be calculated correctly.
2816     QFile::remove("tmp.txt");
2817     QFile file("tmp.txt");
2818     QVERIFY(!file.exists());
2819     QVERIFY(file.open(QIODevice::Append));
2820     QVERIFY(file.exists());
2821     file.write("qt430", 5);
2822     QVERIFY(!file.isSequential());
2823     QCOMPARE(file.pos(), qint64(5));
2824     file.remove();
2825 }
2826
2827 #define FILESIZE 65536 * 3
2828
2829 void tst_QFile::map_data()
2830 {
2831     QTest::addColumn<int>("fileSize");
2832     QTest::addColumn<int>("offset");
2833     QTest::addColumn<int>("size");
2834     QTest::addColumn<QFile::FileError>("error");
2835
2836     QTest::newRow("zero")         << FILESIZE << 0     << FILESIZE         << QFile::NoError;
2837     QTest::newRow("small, but 0") << FILESIZE << 30    << FILESIZE - 30    << QFile::NoError;
2838     QTest::newRow("a page")       << FILESIZE << 4096  << FILESIZE - 4096  << QFile::NoError;
2839     QTest::newRow("+page")        << FILESIZE << 5000  << FILESIZE - 5000  << QFile::NoError;
2840     QTest::newRow("++page")       << FILESIZE << 65576 << FILESIZE - 65576 << QFile::NoError;
2841     QTest::newRow("bad size")     << FILESIZE << 0     << -1               << QFile::ResourceError;
2842     QTest::newRow("bad offset")   << FILESIZE << -1    << 1                << QFile::UnspecifiedError;
2843     QTest::newRow("zerozero")     << FILESIZE << 0     << 0                << QFile::UnspecifiedError;
2844 }
2845
2846 void tst_QFile::map()
2847 {
2848     QFETCH(int, fileSize);
2849     QFETCH(int, offset);
2850     QFETCH(int, size);
2851     QFETCH(QFile::FileError, error);
2852
2853     QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile";
2854
2855 #ifdef Q_OS_WINCE
2856      fileName = QFileInfo(fileName).absoluteFilePath();
2857 #endif
2858
2859     if (QFile::exists(fileName)) {
2860         QVERIFY(QFile::setPermissions(fileName,
2861             QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser));
2862         QFile::remove(fileName);
2863     }
2864     QFile file(fileName);
2865
2866     // invalid, not open
2867     uchar *memory = file.map(0, size);
2868     QVERIFY(!memory);
2869     QCOMPARE(file.error(), QFile::PermissionsError);
2870     QVERIFY(!file.unmap(memory));
2871     QCOMPARE(file.error(), QFile::PermissionsError);
2872
2873     // make a file
2874     QVERIFY(file.open(QFile::ReadWrite));
2875     QVERIFY(file.resize(fileSize));
2876     QVERIFY(file.flush());
2877     file.close();
2878     QVERIFY(file.open(QFile::ReadWrite));
2879     memory = file.map(offset, size);
2880     if (error != QFile::NoError) {
2881         QVERIFY(file.error() != QFile::NoError);
2882         return;
2883     }
2884
2885     QCOMPARE(file.error(), error);
2886     QVERIFY(memory);
2887     memory[0] = 'Q';
2888     QVERIFY(file.unmap(memory));
2889     QCOMPARE(file.error(), QFile::NoError);
2890
2891     // Verify changes were saved
2892     memory = file.map(offset, size);
2893     QCOMPARE(file.error(), QFile::NoError);
2894     QVERIFY(memory);
2895     QVERIFY(memory[0] == 'Q');
2896     QVERIFY(file.unmap(memory));
2897     QCOMPARE(file.error(), QFile::NoError);
2898
2899     // hpux wont let you map multiple times.
2900 #if !defined(Q_OS_HPUX) && !defined(Q_USE_DEPRECATED_MAP_API) && !defined(Q_OS_WINCE)
2901     // exotic test to make sure that multiple maps work
2902
2903     // note: windows ce does not reference count mutliple maps
2904     // it's essentially just the same reference but it 
2905     // cause a resource lock on the file which prevents it 
2906     // from being removed    uchar *memory1 = file.map(0, file.size());
2907     uchar *memory1 = file.map(0, file.size());
2908     QCOMPARE(file.error(), QFile::NoError);
2909     uchar *memory2 = file.map(0, file.size());
2910     QCOMPARE(file.error(), QFile::NoError);
2911     QVERIFY(memory1);
2912     QVERIFY(memory2);
2913     QVERIFY(file.unmap(memory1));
2914     QCOMPARE(file.error(), QFile::NoError);
2915     QVERIFY(file.unmap(memory2));
2916     QCOMPARE(file.error(), QFile::NoError);
2917     memory1 = file.map(0, file.size());
2918     QCOMPARE(file.error(), QFile::NoError);
2919     QVERIFY(memory1);
2920     QVERIFY(file.unmap(memory1));
2921     QCOMPARE(file.error(), QFile::NoError);
2922 #endif
2923
2924     file.close();
2925
2926 #if defined(Q_OS_UNIX)
2927     if (::getuid() != 0)
2928         // root always has permissions
2929 #endif
2930     {
2931         // Change permissions on a file, just to confirm it would fail
2932         QFile::Permissions originalPermissions = file.permissions();
2933         QVERIFY(file.setPermissions(QFile::ReadOther));
2934         QVERIFY(!file.open(QFile::ReadWrite));
2935         memory = file.map(offset, size);
2936         QCOMPARE(file.error(), QFile::PermissionsError);
2937         QVERIFY(!memory);
2938         QVERIFY(file.setPermissions(originalPermissions));
2939     }
2940     QVERIFY(file.remove());
2941 }
2942
2943 void tst_QFile::mapResource_data()
2944 {
2945     QTest::addColumn<int>("offset");
2946     QTest::addColumn<int>("size");
2947     QTest::addColumn<QFile::FileError>("error");
2948     QTest::addColumn<QString>("fileName");
2949
2950     QString validFile = ":/tst_qfileinfo/resources/file1.ext1";
2951     QString invalidFile = ":/tst_qfileinfo/resources/filefoo.ext1";
2952
2953     for (int i = 0; i < 2; ++i) {
2954         QString file = (i == 0) ? validFile : invalidFile;
2955         QTest::newRow("0, 0") << 0 << 0 << QFile::UnspecifiedError << file;
2956         QTest::newRow("0, BIG") << 0 << 4096 << QFile::UnspecifiedError << file;
2957         QTest::newRow("-1, 0") << -1 << 0 << QFile::UnspecifiedError << file;
2958         QTest::newRow("0, -1") << 0 << -1 << QFile::UnspecifiedError << file;
2959     }
2960
2961     QTest::newRow("0, 1") << 0 << 1 << QFile::NoError << validFile;
2962 }
2963
2964 void tst_QFile::mapResource()
2965 {
2966     QFETCH(QString, fileName);
2967     QFETCH(int, offset);
2968     QFETCH(int, size);
2969     QFETCH(QFile::FileError, error);
2970
2971     QFile file(fileName);
2972     uchar *memory = file.map(offset, size);
2973     QCOMPARE(file.error(), error);
2974     QVERIFY((error == QFile::NoError) ? (memory != 0) : (memory == 0));
2975     if (error == QFile::NoError)
2976         QCOMPARE(QString(memory[0]), QString::number(offset + 1));
2977     QVERIFY(file.unmap(memory));
2978 }
2979
2980 void tst_QFile::mapOpenMode_data()
2981 {
2982     QTest::addColumn<int>("openMode");
2983
2984     QTest::newRow("ReadOnly") << int(QIODevice::ReadOnly);
2985     //QTest::newRow("WriteOnly") << int(QIODevice::WriteOnly); // this doesn't make sense
2986     QTest::newRow("ReadWrite") << int(QIODevice::ReadWrite);
2987     QTest::newRow("ReadOnly,Unbuffered") << int(QIODevice::ReadOnly | QIODevice::Unbuffered);
2988     QTest::newRow("ReadWrite,Unbuffered") << int(QIODevice::ReadWrite | QIODevice::Unbuffered);
2989 }
2990
2991 void tst_QFile::mapOpenMode()
2992 {
2993     QFETCH(int, openMode);
2994     static const qint64 fileSize = 4096;
2995
2996     QByteArray pattern(fileSize, 'A');
2997
2998     QString fileName = QDir::currentPath() + '/' + "qfile_map_testfile";
2999     if (QFile::exists(fileName)) {
3000         QVERIFY(QFile::setPermissions(fileName,
3001             QFile::WriteOwner | QFile::ReadOwner | QFile::WriteUser | QFile::ReadUser));
3002         QFile::remove(fileName);
3003     }
3004     QFile file(fileName);
3005
3006     // make a file
3007     QVERIFY(file.open(QFile::ReadWrite));
3008     QVERIFY(file.write(pattern));
3009     QVERIFY(file.flush());
3010     file.close();
3011
3012     // open according to our mode
3013     QVERIFY(file.open(QIODevice::OpenMode(openMode)));
3014
3015     uchar *memory = file.map(0, fileSize);
3016     QVERIFY(memory);
3017     QVERIFY(memcmp(memory, pattern, fileSize) == 0);
3018
3019     if (openMode & QIODevice::WriteOnly) {
3020         // try to write to the file
3021         *memory = 'a';
3022         file.unmap(memory);
3023         file.close();
3024         file.open(QIODevice::OpenMode(openMode));
3025         file.seek(0);
3026         char c;
3027         QVERIFY(file.getChar(&c));
3028         QCOMPARE(c, 'a');
3029     }
3030
3031     file.close();
3032 }
3033
3034 void tst_QFile::openDirectory()
3035 {
3036     QFile f1(QFINDTESTDATA("resources"));
3037     // it's a directory, it must exist
3038     QVERIFY(f1.exists());
3039
3040     // ...but not be openable
3041     QVERIFY(!f1.open(QIODevice::ReadOnly));
3042     f1.close();
3043     QVERIFY(!f1.open(QIODevice::ReadOnly|QIODevice::Unbuffered));
3044     f1.close();
3045     QVERIFY(!f1.open(QIODevice::ReadWrite));
3046     f1.close();
3047     QVERIFY(!f1.open(QIODevice::WriteOnly));
3048     f1.close();
3049     QVERIFY(!f1.open(QIODevice::WriteOnly|QIODevice::Unbuffered));
3050     f1.close();
3051 }
3052
3053 static qint64 streamExpectedSize(int fd)
3054 {
3055     QT_STATBUF sb;
3056     if (QT_FSTAT(fd, &sb) != -1)
3057         return sb.st_size;
3058     return 0;
3059 }
3060
3061 static qint64 streamCurrentPosition(int fd)
3062 {
3063     QT_OFF_T pos = QT_LSEEK(fd, 0, SEEK_CUR);
3064     if (pos != -1)
3065         return pos;
3066     return 0;
3067 }
3068
3069 static qint64 streamCurrentPosition(FILE *f)
3070 {
3071     QT_OFF_T pos = QT_FTELL(f);
3072     if (pos != -1)
3073         return pos;
3074     return 0;
3075 }
3076
3077 class MessageHandler {
3078 public:
3079     MessageHandler(QtMessageHandler messageHandler = handler)
3080     {
3081         ok = true;
3082         oldMessageHandler = qInstallMessageHandler(messageHandler);
3083     }
3084
3085     ~MessageHandler()
3086     {
3087         qInstallMessageHandler(oldMessageHandler);
3088     }
3089
3090     static bool testPassed()
3091     {
3092         return ok;
3093     }
3094 protected:
3095     static void handler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
3096     {
3097         if (msg == QString::fromLatin1("QIODevice::seek: Cannot call seek on a sequential device"))
3098             ok = false;
3099         // Defer to old message handler.
3100         if (oldMessageHandler)
3101             oldMessageHandler(type, context, msg);
3102     }
3103
3104     static QtMessageHandler oldMessageHandler;
3105     static bool ok;
3106 };
3107
3108 bool MessageHandler::ok = true;
3109 QtMessageHandler MessageHandler::oldMessageHandler = 0;
3110
3111 void tst_QFile::openStandardStreamsFileDescriptors()
3112 {
3113 #ifdef Q_OS_WINCE
3114     //allthough Windows CE (not mobile!) has functions that allow redirecting
3115     //the standard file descriptors to a file (see SetStdioPathW/GetStdioPathW)
3116     //it does not have functions to simply open them like below .
3117     QSKIP("Opening standard streams on Windows CE via descriptor not implemented");
3118 #endif
3119
3120     // Check that QIODevice::seek() isn't called when opening a sequential device (QFile).
3121     MessageHandler msgHandler;
3122
3123     {
3124         QFile in;
3125         in.open(STDIN_FILENO, QIODevice::ReadOnly);
3126         QCOMPARE( in.pos(), streamCurrentPosition(STDIN_FILENO) );
3127         QCOMPARE( in.size(), streamExpectedSize(STDIN_FILENO) );
3128     }
3129
3130     {
3131         QFile out;
3132         QVERIFY(out.open(STDOUT_FILENO, QIODevice::WriteOnly));
3133         QCOMPARE( out.pos(), streamCurrentPosition(STDOUT_FILENO) );
3134         QCOMPARE( out.size(), streamExpectedSize(STDOUT_FILENO) );
3135     }
3136
3137     {
3138         QFile err;
3139         err.open(STDERR_FILENO, QIODevice::WriteOnly);
3140         QCOMPARE( err.pos(), streamCurrentPosition(STDERR_FILENO) );
3141         QCOMPARE( err.size(), streamExpectedSize(STDERR_FILENO) );
3142     }
3143
3144     QVERIFY(msgHandler.testPassed());
3145 }
3146
3147 void tst_QFile::openStandardStreamsBufferedStreams()
3148 {
3149 #ifdef Q_OS_WINCE
3150     QSKIP("Not tested on Windows CE.");
3151 #endif
3152     // Check that QIODevice::seek() isn't called when opening a sequential device (QFile).
3153     MessageHandler msgHandler;
3154
3155     // Using streams
3156     {
3157         QFile in;
3158         in.open(stdin, QIODevice::ReadOnly);
3159         QCOMPARE( in.pos(), streamCurrentPosition(stdin) );
3160         QCOMPARE( in.size(), streamExpectedSize(QT_FILENO(stdin)) );
3161     }
3162
3163     {
3164         QFile out;
3165         out.open(stdout, QIODevice::WriteOnly);
3166         QCOMPARE( out.pos(), streamCurrentPosition(stdout) );
3167         QCOMPARE( out.size(), streamExpectedSize(QT_FILENO(stdout)) );
3168     }
3169
3170     {
3171         QFile err;
3172         err.open(stderr, QIODevice::WriteOnly);
3173         QCOMPARE( err.pos(), streamCurrentPosition(stderr) );
3174         QCOMPARE( err.size(), streamExpectedSize(QT_FILENO(stderr)) );
3175     }
3176
3177     QVERIFY(msgHandler.testPassed());
3178 }
3179
3180 void tst_QFile::writeNothing()
3181 {
3182     for (int i = 0; i < NumberOfFileTypes; ++i) {
3183         QFile file("file.txt");
3184         QVERIFY( openFile(file, QIODevice::WriteOnly | QIODevice::Unbuffered, FileType(i)) );
3185         QVERIFY( 0 == file.write((char *)0, 0) );
3186         QCOMPARE( file.error(), QFile::NoError );
3187         closeFile(file);
3188     }
3189 }
3190
3191 void tst_QFile::resize_data()
3192 {
3193     QTest::addColumn<int>("filetype");
3194
3195     QTest::newRow("native") << int(OpenQFile);
3196     QTest::newRow("fileno") << int(OpenFd);
3197     QTest::newRow("stream") << int(OpenStream);
3198 }
3199
3200 void tst_QFile::resize()
3201 {
3202     QFETCH(int, filetype);
3203     QString filename(QLatin1String("file.txt"));
3204     QFile file(filename);
3205     QVERIFY(openFile(file, QIODevice::ReadWrite, FileType(filetype)));
3206     QVERIFY(file.resize(8));
3207     QCOMPARE(file.size(), qint64(8));
3208     closeFile(file);
3209     QFile::resize(filename, 4);
3210     QCOMPARE(QFileInfo(filename).size(), qint64(4));
3211     QVERIFY(QFile::remove(filename));
3212 }
3213
3214 void tst_QFile::objectConstructors()
3215 {
3216     QObject ob;
3217     QFile* file1 = new QFile(QFINDTESTDATA("testfile.txt"), &ob);
3218     QFile* file2 = new QFile(&ob);
3219     QVERIFY(file1->exists());
3220     QVERIFY(!file2->exists());
3221 }
3222
3223 void tst_QFile::caseSensitivity()
3224 {
3225 #if defined(Q_OS_WIN) || defined(Q_OS_MAC)
3226     const bool caseSensitive = false;
3227 #else
3228     const bool caseSensitive = true;
3229 #endif
3230     QByteArray testData("a little test");
3231     QString filename("File.txt");
3232     {
3233         QFile f(filename);
3234         QVERIFY(f.open(QIODevice::WriteOnly));
3235         QVERIFY(f.write(testData));
3236         f.close();
3237     }
3238     QStringList alternates;
3239     QFileInfo fi(filename);
3240     QVERIFY(fi.exists());
3241     alternates << "file.txt" << "File.TXT" << "fIlE.TxT" << fi.absoluteFilePath().toUpper() << fi.absoluteFilePath().toLower();
3242     foreach (QString alt, alternates) {
3243         QFileInfo fi2(alt);
3244         QCOMPARE(fi2.exists(), !caseSensitive);
3245         QCOMPARE(fi.size() == fi2.size(), !caseSensitive);
3246         QFile f2(alt);
3247         QCOMPARE(f2.open(QIODevice::ReadOnly), !caseSensitive);
3248         if (!caseSensitive)
3249             QCOMPARE(f2.readAll(), testData);
3250     }
3251 }
3252
3253 //MSVCRT asserts when any function is called with a closed file handle.
3254 //This replaces the default crashing error handler with one that ignores the error (allowing EBADF to be returned)
3255 class AutoIgnoreInvalidParameter
3256 {
3257 public:
3258 #if defined(Q_OS_WIN) && defined (Q_CC_MSVC)
3259     static void ignore_invalid_parameter(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t) {}
3260     AutoIgnoreInvalidParameter()
3261     {
3262         oldHandler = _set_invalid_parameter_handler(ignore_invalid_parameter);
3263         //also disable the abort/retry/ignore popup
3264         oldReportMode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
3265     }
3266     ~AutoIgnoreInvalidParameter()
3267     {
3268         //restore previous settings
3269         _set_invalid_parameter_handler(oldHandler);
3270         _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
3271     }
3272     _invalid_parameter_handler oldHandler;
3273     int oldReportMode;
3274 #endif
3275 };
3276
3277 void tst_QFile::autocloseHandle()
3278 {
3279     {
3280         QFile file("readonlyfile");
3281         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenFd, QFile::AutoCloseHandle));
3282         int fd = fd_;
3283         QCOMPARE(file.handle(), fd);
3284         file.close();
3285         fd_ = -1;
3286         QCOMPARE(file.handle(), -1);
3287         AutoIgnoreInvalidParameter a;
3288         Q_UNUSED(a);
3289         //file is closed, read should fail
3290         char buf;
3291         QCOMPARE((int)QT_READ(fd, &buf, 1), -1);
3292         QVERIFY(errno = EBADF);
3293     }
3294
3295     {
3296         QFile file("readonlyfile");
3297         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenFd, QFile::DontCloseHandle));
3298         QCOMPARE(file.handle(), fd_);
3299         file.close();
3300         QCOMPARE(file.handle(), -1);
3301         //file is not closed, read should succeed
3302         char buf;
3303         QCOMPARE((int)QT_READ(fd_, &buf, 1), 1);
3304         QT_CLOSE(fd_);
3305         fd_ = -1;
3306     }
3307
3308     {
3309         QFile file("readonlyfile");
3310         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenStream, QFile::AutoCloseHandle));
3311         int fd = QT_FILENO(stream_);
3312         QCOMPARE(file.handle(), fd);
3313         file.close();
3314         stream_ = 0;
3315         QCOMPARE(file.handle(), -1);
3316         AutoIgnoreInvalidParameter a;
3317         Q_UNUSED(a);
3318         //file is closed, read should fail
3319         char buf;
3320         QCOMPARE((int)QT_READ(fd, &buf, 1), -1); //not using fread because the FILE* was freed by fclose
3321     }
3322
3323     {
3324         QFile file("readonlyfile");
3325         QVERIFY(openFile(file, QIODevice::ReadOnly, OpenStream, QFile::DontCloseHandle));
3326         QCOMPARE(file.handle(), QT_FILENO(stream_));
3327         file.close();
3328         QCOMPARE(file.handle(), -1);
3329         //file is not closed, read should succeed
3330         char buf;
3331         QCOMPARE(int(::fread(&buf, 1, 1, stream_)), 1);
3332         ::fclose(stream_);
3333         stream_ = 0;
3334     }
3335 }
3336
3337 QTEST_MAIN(tst_QFile)
3338 #include "tst_qfile.moc"