1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the FOO module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtCore/private/qabstractfileengine_p.h>
30#include <QtCore/private/qfsfileengine_p.h>
31
32#include <QtCore/QMutex>
33#include <QtCore/QMutexLocker>
34#include <QtCore/QSharedPointer>
35#include <QtCore/QScopedPointer>
36#include <QtCore/QHash>
37#include <QtCore/QDir>
38#include <QtCore/QDirIterator>
39
40#include <QtTest/QTest>
41
42#include <QtCore/QDebug>
43#include "../../../../shared/filesystem.h"
44
45class tst_QAbstractFileEngine
46 : public QObject
47{
48 Q_OBJECT
49public slots:
50 void initTestCase();
51 void cleanupTestCase();
52
53private slots:
54 void customHandler();
55
56 void fileIO_data();
57 void fileIO();
58
59 void mounting_data();
60 void mounting();
61private:
62 QStringList filesForRemoval;
63 QSharedPointer<QTemporaryDir> m_currentDir;
64 QString m_previousCurrent;
65};
66
67class ReferenceFileEngine
68 : public QAbstractFileEngine
69{
70public:
71 ReferenceFileEngine(const QString &fileName)
72 : fileName_(QDir::cleanPath(path: fileName))
73 , position_(-1)
74 , openForRead_(false)
75 , openForWrite_(false)
76 {
77 }
78
79 bool open(QIODevice::OpenMode openMode)
80 {
81 if (openForRead_ || openForWrite_) {
82 qWarning(msg: "%s: file is already open for %s",
83 Q_FUNC_INFO,
84 (openForRead_ ? "reading" : "writing"));
85 return false;
86 }
87
88 openFile_ = resolveFile(create: openMode & QIODevice::WriteOnly);
89 if (!openFile_)
90 return false;
91
92 position_ = 0;
93 if (openMode & QIODevice::ReadOnly)
94 openForRead_ = true;
95
96 if (openMode & QIODevice::WriteOnly) {
97 openForWrite_ = true;
98
99 QMutexLocker lock(&openFile_->mutex);
100 if (openMode & QIODevice::Truncate
101 || !(openForRead_ || openMode & QIODevice::Append))
102 openFile_->content.clear();
103
104 if (openMode & QIODevice::Append)
105 position_ = openFile_->content.size();
106 }
107
108 return true;
109 }
110
111 bool close()
112 {
113 openFile_.clear();
114
115 openForRead_ = false;
116 openForWrite_ = false;
117 position_ = -1;
118
119 return true;
120 }
121
122 qint64 size() const
123 {
124 QSharedPointer<File> file = resolveFile(create: false);
125 if (!file)
126 return 0;
127
128 QMutexLocker lock(&file->mutex);
129 return file->content.size();
130 }
131
132 qint64 pos() const
133 {
134 if (!openForRead_ && !openForWrite_) {
135 qWarning(msg: "%s: file is not open", Q_FUNC_INFO);
136 return -1;
137 }
138 return position_;
139 }
140
141 bool seek(qint64 pos)
142 {
143 if (!openForRead_ && !openForWrite_) {
144 qWarning(msg: "%s: file is not open", Q_FUNC_INFO);
145 return false;
146 }
147
148 if (pos >= 0) {
149 position_ = pos;
150 return true;
151 }
152
153 return false;
154 }
155
156 bool flush()
157 {
158 if (!openForRead_ && !openForWrite_) {
159 qWarning(msg: "%s: file is not open", Q_FUNC_INFO);
160 return false;
161 }
162
163 return true;
164 }
165
166 bool remove()
167 {
168 QMutexLocker lock(&fileSystemMutex);
169 int count = fileSystem.remove(key: fileName_);
170
171 return (count == 1);
172 }
173
174 bool copy(const QString &newName)
175 {
176 QMutexLocker lock(&fileSystemMutex);
177 if (!fileSystem.contains(key: fileName_)
178 || fileSystem.contains(key: newName))
179 return false;
180
181 fileSystem.insert(key: newName, value: fileSystem.value(key: fileName_));
182 return true;
183 }
184
185 bool rename(const QString &newName)
186 {
187 QMutexLocker lock(&fileSystemMutex);
188 if (!fileSystem.contains(key: fileName_)
189 || fileSystem.contains(key: newName))
190 return false;
191
192 fileSystem.insert(key: newName, value: fileSystem.take(key: fileName_));
193 return true;
194 }
195
196 // bool link(const QString &newName)
197 // {
198 // Q_UNUSED(newName)
199 // return false;
200 // }
201
202 // bool mkdir(const QString &dirName, bool createParentDirectories) const
203 // {
204 // Q_UNUSED(dirName)
205 // Q_UNUSED(createParentDirectories)
206
207 // return false;
208 // }
209
210 // bool rmdir(const QString &dirName, bool recurseParentDirectories) const
211 // {
212 // Q_UNUSED(dirName)
213 // Q_UNUSED(recurseParentDirectories)
214
215 // return false;
216 // }
217
218 bool setSize(qint64 size)
219 {
220 if (size < 0)
221 return false;
222
223 QSharedPointer<File> file = resolveFile(create: false);
224 if (!file)
225 return false;
226
227 QMutexLocker lock(&file->mutex);
228 file->content.resize(size);
229
230 if (openForRead_ || openForWrite_)
231 if (position_ > size)
232 position_ = size;
233
234 return (file->content.size() == size);
235 }
236
237 FileFlags fileFlags(FileFlags type) const
238 {
239 QSharedPointer<File> file = resolveFile(create: false);
240 if (file) {
241 QMutexLocker lock(&file->mutex);
242 return (file->fileFlags & type);
243 }
244
245 return FileFlags();
246 }
247
248 // bool setPermissions(uint perms)
249 // {
250 // Q_UNUSED(perms)
251
252 // return false;
253 // }
254
255 QString fileName(FileName file) const
256 {
257 switch (file) {
258 case DefaultName:
259 return QLatin1String("DefaultName");
260 case BaseName:
261 return QLatin1String("BaseName");
262 case PathName:
263 return QLatin1String("PathName");
264 case AbsoluteName:
265 return QLatin1String("AbsoluteName");
266 case AbsolutePathName:
267 return QLatin1String("AbsolutePathName");
268 case LinkName:
269 return QLatin1String("LinkName");
270 case CanonicalName:
271 return QLatin1String("CanonicalName");
272 case CanonicalPathName:
273 return QLatin1String("CanonicalPathName");
274 case BundleName:
275 return QLatin1String("BundleName");
276
277 default:
278 break;
279 }
280
281 return QString();
282 }
283
284 uint ownerId(FileOwner owner) const
285 {
286 QSharedPointer<File> file = resolveFile(create: false);
287 if (file) {
288 switch (owner) {
289 case OwnerUser:
290 {
291 QMutexLocker lock(&file->mutex);
292 return file->userId;
293 }
294 case OwnerGroup:
295 {
296 QMutexLocker lock(&file->mutex);
297 return file->groupId;
298 }
299 }
300 }
301
302 return -2;
303 }
304
305 QString owner(FileOwner owner) const
306 {
307 QSharedPointer<File> file = resolveFile(create: false);
308 if (file) {
309 uint ownerId;
310 switch (owner) {
311 case OwnerUser:
312 {
313 QMutexLocker lock(&file->mutex);
314 ownerId = file->userId;
315 }
316
317 {
318 QMutexLocker lock(&fileSystemMutex);
319 return fileSystemUsers.value(key: ownerId);
320 }
321
322 case OwnerGroup:
323 {
324 QMutexLocker lock(&file->mutex);
325 ownerId = file->groupId;
326 }
327
328 {
329 QMutexLocker lock(&fileSystemMutex);
330 return fileSystemGroups.value(key: ownerId);
331 }
332 }
333 }
334
335 return QString();
336 }
337
338 QDateTime fileTime(FileTime time) const
339 {
340 QSharedPointer<File> file = resolveFile(create: false);
341 if (file) {
342 QMutexLocker lock(&file->mutex);
343 switch (time) {
344 case BirthTime:
345 return file->birth;
346 case MetadataChangeTime:
347 return file->change;
348 case ModificationTime:
349 return file->modification;
350 case AccessTime:
351 return file->access;
352 }
353 }
354
355 return QDateTime();
356 }
357
358 bool setFileTime(const QDateTime &newDate, FileTime time)
359 {
360 Q_UNUSED(newDate);
361 Q_UNUSED(time);
362 return false;
363 }
364
365 void setFileName(const QString &file)
366 {
367 if (openForRead_ || openForWrite_)
368 qWarning(msg: "%s: Can't set file name while file is open", Q_FUNC_INFO);
369 else
370 fileName_ = file;
371 }
372
373 // typedef QAbstractFileEngineIterator Iterator;
374 // Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames)
375 // {
376 // Q_UNUSED(filters)
377 // Q_UNUSED(filterNames)
378
379 // return 0;
380 // }
381
382 // Iterator *endEntryList()
383 // {
384 // return 0;
385 // }
386
387 qint64 read(char *data, qint64 maxLen)
388 {
389 if (!openForRead_) {
390 qWarning(msg: "%s: file must be open for reading", Q_FUNC_INFO);
391 return -1;
392 }
393
394 if (openFile_.isNull()) {
395 qWarning(msg: "%s: file must not be null", Q_FUNC_INFO);
396 return -1;
397 }
398
399 QMutexLocker lock(&openFile_->mutex);
400 qint64 readSize = qMin(a: openFile_->content.size() - position_, b: maxLen);
401 if (readSize < 0)
402 return -1;
403
404 memcpy(dest: data, src: openFile_->content.constData() + position_, n: readSize);
405 position_ += readSize;
406
407 return readSize;
408 }
409
410 qint64 write(const char *data, qint64 length)
411 {
412 if (!openForWrite_) {
413 qWarning(msg: "%s: file must be open for writing", Q_FUNC_INFO);
414 return -1;
415 }
416
417 if (openFile_.isNull()) {
418 qWarning(msg: "%s: file must not be null", Q_FUNC_INFO);
419 return -1;
420 }
421
422 if (length < 0)
423 return -1;
424
425 QMutexLocker lock(&openFile_->mutex);
426 if (openFile_->content.size() == position_)
427 openFile_->content.append(s: data, len: length);
428 else {
429 if (position_ + length > openFile_->content.size())
430 openFile_->content.resize(size: position_ + length);
431 openFile_->content.replace(index: position_, len: length, s: data, alen: length);
432 }
433
434 qint64 writeSize = qMin(a: length, b: openFile_->content.size() - position_);
435 position_ += writeSize;
436
437 return writeSize;
438 }
439
440protected:
441 // void setError(QFile::FileError error, const QString &str);
442
443 struct File
444 {
445 File()
446 : userId(0)
447 , groupId(0)
448 , fileFlags(
449 ReadOwnerPerm | WriteOwnerPerm | ExeOwnerPerm
450 | ReadUserPerm | WriteUserPerm | ExeUserPerm
451 | ReadGroupPerm | WriteGroupPerm | ExeGroupPerm
452 | ReadOtherPerm | WriteOtherPerm | ExeOtherPerm
453 | FileType | ExistsFlag)
454 {
455 }
456
457 QMutex mutex;
458
459 uint userId, groupId;
460 QAbstractFileEngine::FileFlags fileFlags;
461 QDateTime birth, change, modification, access;
462
463 QByteArray content;
464 };
465
466 QSharedPointer<File> resolveFile(bool create) const
467 {
468 if (openForRead_ || openForWrite_) {
469 if (!openFile_)
470 qWarning(msg: "%s: file should not be null", Q_FUNC_INFO);
471 return openFile_;
472 }
473
474 QMutexLocker lock(&fileSystemMutex);
475 if (create) {
476 QSharedPointer<File> &p = fileSystem[fileName_];
477 if (p.isNull())
478 p = QSharedPointer<File>::create();
479 return p;
480 }
481
482 return fileSystem.value(key: fileName_);
483 }
484
485 static QMutex fileSystemMutex;
486 static QHash<uint, QString> fileSystemUsers, fileSystemGroups;
487 static QHash<QString, QSharedPointer<File> > fileSystem;
488
489private:
490 QString fileName_;
491 qint64 position_;
492 bool openForRead_;
493 bool openForWrite_;
494
495 mutable QSharedPointer<File> openFile_;
496};
497
498class MountingFileEngine : public QFSFileEngine
499{
500public:
501 class Iterator : public QAbstractFileEngineIterator
502 {
503 public:
504 Iterator(QDir::Filters filters, const QStringList &filterNames)
505 : QAbstractFileEngineIterator(filters, filterNames)
506 {
507 names.append(t: "foo");
508 names.append(t: "bar");
509 index = -1;
510 }
511 QString currentFileName() const
512 {
513 return names.at(i: index);
514 }
515 bool hasNext() const
516 {
517 return index < names.size() - 1;
518 }
519 QString next()
520 {
521 if (!hasNext())
522 return QString();
523 ++index;
524 return currentFilePath();
525 }
526 QStringList names;
527 int index;
528 };
529 MountingFileEngine(QString fileName)
530 : QFSFileEngine(fileName)
531 {
532 }
533 Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames)
534 {
535 return new Iterator(filters, filterNames);
536 }
537 FileFlags fileFlags(FileFlags type) const
538 {
539 if (fileName(file: DefaultName).endsWith(s: ".tar")) {
540 FileFlags ret = QFSFileEngine::fileFlags(type);
541 //make this file in file system appear to be a directory
542 ret &= ~FileType;
543 ret |= DirectoryType;
544 return ret;
545 } else {
546 //file inside the archive
547 return ExistsFlag | FileType;
548 }
549 }
550};
551
552QMutex ReferenceFileEngine::fileSystemMutex;
553QHash<uint, QString> ReferenceFileEngine::fileSystemUsers, ReferenceFileEngine::fileSystemGroups;
554QHash<QString, QSharedPointer<ReferenceFileEngine::File> > ReferenceFileEngine::fileSystem;
555
556class FileEngineHandler
557 : QAbstractFileEngineHandler
558{
559 QAbstractFileEngine *create(const QString &fileName) const
560 {
561 if (fileName.endsWith(s: ".tar") || fileName.contains(s: ".tar/"))
562 return new MountingFileEngine(fileName);
563 if (fileName.startsWith(s: "QFSFileEngine:"))
564 return new QFSFileEngine(fileName.mid(position: 14));
565 if (fileName.startsWith(s: "reference-file-engine:"))
566 return new ReferenceFileEngine(fileName.mid(position: 22));
567 if (fileName.startsWith(s: "resource:"))
568 return QAbstractFileEngine::create(fileName: QLatin1String(":/tst_qabstractfileengine/resources/") + fileName.mid(position: 9));
569 return 0;
570 }
571};
572
573void tst_QAbstractFileEngine::initTestCase()
574{
575 m_previousCurrent = QDir::currentPath();
576 m_currentDir = QSharedPointer<QTemporaryDir>::create();
577 QVERIFY2(!m_currentDir.isNull(), qPrintable("Could not create current directory."));
578 QDir::setCurrent(m_currentDir->path());
579}
580
581void tst_QAbstractFileEngine::cleanupTestCase()
582{
583 bool failed = false;
584
585 FileEngineHandler handler;
586 Q_FOREACH(QString file, filesForRemoval)
587 if (!QFile::remove(fileName: file)
588 || QFile::exists(fileName: file)) {
589 failed = true;
590 qDebug() << "Couldn't remove file:" << file;
591 }
592
593 QVERIFY(!failed);
594
595 QDir::setCurrent(m_previousCurrent);
596}
597
598void tst_QAbstractFileEngine::customHandler()
599{
600 QScopedPointer<QAbstractFileEngine> file;
601 {
602 file.reset(other: QAbstractFileEngine::create(fileName: "resource:file.txt"));
603
604 QVERIFY(file);
605 }
606
607 {
608 FileEngineHandler handler;
609
610 QFile file("resource:file.txt");
611 QVERIFY(file.exists());
612 }
613
614 {
615 QFile file("resource:file.txt");
616 QVERIFY(!file.exists());
617 }
618}
619
620void tst_QAbstractFileEngine::fileIO_data()
621{
622 QTest::addColumn<QString>(name: "fileName");
623 QTest::addColumn<QByteArray>(name: "readContent");
624 QTest::addColumn<QByteArray>(name: "writeContent");
625 QTest::addColumn<bool>(name: "fileExists");
626
627 QString resourceTxtFile(":/tst_qabstractfileengine/resources/file.txt");
628 QByteArray readContent("This is a simple text file.\n");
629 QByteArray writeContent("This contains two lines of text.\n");
630
631 QTest::newRow(dataTag: "resource") << resourceTxtFile << readContent << QByteArray() << true;
632 QTest::newRow(dataTag: "native") << "native-file.txt" << readContent << writeContent << false;
633 QTest::newRow(dataTag: "Forced QFSFileEngine") << "QFSFileEngine:QFSFileEngine-file.txt" << readContent << writeContent << false;
634 QTest::newRow(dataTag: "Custom FE") << "reference-file-engine:file.txt" << readContent << writeContent << false;
635
636 QTest::newRow(dataTag: "Forced QFSFileEngine (native)") << "QFSFileEngine:native-file.txt" << readContent << writeContent << true;
637 QTest::newRow(dataTag: "native (Forced QFSFileEngine)") << "QFSFileEngine-file.txt" << readContent << writeContent << true;
638 QTest::newRow(dataTag: "Custom FE (2)") << "reference-file-engine:file.txt" << readContent << writeContent << true;
639}
640
641void tst_QAbstractFileEngine::fileIO()
642{
643 QFETCH(QString, fileName);
644 QFETCH(QByteArray, readContent);
645 QFETCH(QByteArray, writeContent);
646 QFETCH(bool, fileExists);
647
648 FileEngineHandler handler;
649
650
651 {
652 QFile file(fileName);
653 QCOMPARE(file.exists(), fileExists);
654
655 if (!fileExists) {
656 QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Unbuffered));
657 filesForRemoval.append(t: fileName);
658
659 QCOMPARE(file.write(readContent), qint64(readContent.size()));
660 }
661 }
662
663 //
664 // File content is: readContent
665 //
666
667 qint64 fileSize = readContent.size();
668 {
669 // Reading
670 QFile file(fileName);
671 QVERIFY(!file.isOpen());
672
673 /* For an exact match, this test requires the repository to
674 * be checked out with UNIX-style line endings on Windows.
675 * Try to succeed also for the common case of checking out with autocrlf
676 * by reading the file as text and checking if the size matches
677 * the original size + the '\r' characters added by autocrlf. */
678
679 QFile::OpenMode openMode = QIODevice::ReadOnly | QIODevice::Unbuffered;
680#ifdef Q_OS_WIN
681 openMode |= QIODevice::Text;
682#endif
683 QVERIFY(file.open(openMode));
684 QVERIFY(file.isOpen());
685#ifdef Q_OS_WIN
686 const qint64 convertedSize = fileSize + readContent.count('\n');
687 if (file.size() == convertedSize)
688 fileSize = convertedSize;
689#endif
690 QCOMPARE(file.size(), fileSize);
691 QCOMPARE(file.pos(), qint64(0));
692
693 QCOMPARE(file.size(), fileSize);
694 QCOMPARE(file.readAll(), readContent);
695 QCOMPARE(file.pos(), fileSize);
696
697 file.close();
698 QVERIFY(!file.isOpen());
699 QCOMPARE(file.size(), fileSize);
700 }
701
702 if (writeContent.isEmpty())
703 return;
704
705 {
706 // Writing / appending
707 QFile file(fileName);
708
709 QVERIFY(!file.isOpen());
710 QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered));
711
712 QVERIFY(file.isOpen());
713 QCOMPARE(file.size(), fileSize);
714 QCOMPARE(file.pos(), fileSize);
715
716 QCOMPARE(file.write(writeContent), qint64(writeContent.size()));
717
718 fileSize += writeContent.size();
719 QCOMPARE(file.pos(), fileSize);
720 QCOMPARE(file.size(), fileSize);
721
722 file.close();
723 QVERIFY(!file.isOpen());
724 QCOMPARE(file.size(), fileSize);
725 }
726
727 //
728 // File content is: readContent + writeContent
729 //
730
731 {
732 // Reading and Writing
733 QFile file(fileName);
734
735 QVERIFY(!file.isOpen());
736 QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered));
737
738 QVERIFY(file.isOpen());
739 QCOMPARE(file.size(), fileSize);
740 QCOMPARE(file.pos(), qint64(0));
741
742 QCOMPARE(file.readAll(), readContent + writeContent);
743 QCOMPARE(file.pos(), fileSize);
744 QCOMPARE(file.size(), fileSize);
745
746 QVERIFY(file.seek(writeContent.size()));
747 QCOMPARE(file.pos(), qint64(writeContent.size()));
748 QCOMPARE(file.size(), fileSize);
749
750 QCOMPARE(file.write(readContent), qint64(readContent.size()));
751 QCOMPARE(file.pos(), fileSize);
752 QCOMPARE(file.size(), fileSize);
753
754 QVERIFY(file.seek(0));
755 QCOMPARE(file.pos(), qint64(0));
756 QCOMPARE(file.size(), fileSize);
757
758 QCOMPARE(file.write(writeContent), qint64(writeContent.size()));
759 QCOMPARE(file.pos(), qint64(writeContent.size()));
760 QCOMPARE(file.size(), fileSize);
761
762 QVERIFY(file.seek(0));
763 QCOMPARE(file.read(writeContent.size()), writeContent);
764 QCOMPARE(file.pos(), qint64(writeContent.size()));
765 QCOMPARE(file.size(), fileSize);
766
767 QCOMPARE(file.readAll(), readContent);
768 QCOMPARE(file.pos(), fileSize);
769 QCOMPARE(file.size(), fileSize);
770
771 file.close();
772 QVERIFY(!file.isOpen());
773 QCOMPARE(file.size(), fileSize);
774 }
775
776 //
777 // File content is: writeContent + readContent
778 //
779
780 {
781 // Writing
782 QFile file(fileName);
783
784 QVERIFY(!file.isOpen());
785 QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered));
786
787 QVERIFY(file.isOpen());
788 QCOMPARE(file.size(), fileSize);
789 QCOMPARE(file.pos(), qint64(0));
790
791 QCOMPARE(file.write(writeContent), qint64(writeContent.size()));
792 QCOMPARE(file.pos(), qint64(writeContent.size()));
793 QCOMPARE(file.size(), fileSize);
794
795 QVERIFY(file.resize(writeContent.size()));
796 QCOMPARE(file.size(), qint64(writeContent.size()));
797
798 file.close();
799 QVERIFY(!file.isOpen());
800 QCOMPARE(file.size(), qint64(writeContent.size()));
801
802 QVERIFY(file.resize(fileSize));
803 QCOMPARE(file.size(), fileSize);
804 }
805
806 //
807 // File content is: writeContent + <undefined>
808 // File size is : (readContent + writeContent).size()
809 //
810
811 {
812 // Writing / extending
813 QFile file(fileName);
814
815 QVERIFY(!file.isOpen());
816 QVERIFY(file.open(QIODevice::ReadWrite | QIODevice::Unbuffered));
817
818 QVERIFY(file.isOpen());
819 QCOMPARE(file.size(), fileSize);
820 QCOMPARE(file.pos(), qint64(0));
821
822 QVERIFY(file.seek(1024));
823 QCOMPARE(file.pos(), qint64(1024));
824 QCOMPARE(file.size(), fileSize);
825
826 fileSize = 1024 + writeContent.size();
827 QCOMPARE(file.write(writeContent), qint64(writeContent.size()));
828 QCOMPARE(file.pos(), fileSize);
829 QCOMPARE(file.size(), fileSize);
830
831 QVERIFY(file.seek(1028));
832 QCOMPARE(file.pos(), qint64(1028));
833 QCOMPARE(file.size(), fileSize);
834
835 fileSize = 1028 + writeContent.size();
836 QCOMPARE(file.write(writeContent), qint64(writeContent.size()));
837 QCOMPARE(file.pos(), fileSize);
838 QCOMPARE(file.size(), fileSize);
839
840 file.close();
841 QVERIFY(!file.isOpen());
842 QCOMPARE(file.size(), fileSize);
843 }
844
845 //
846 // File content is: writeContent + <undefined> + writeContent
847 // File size is : 1024 + writeContent.size()
848 //
849
850 {
851 // Writing / truncating
852 QFile file(fileName);
853
854 QVERIFY(!file.isOpen());
855 QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Unbuffered));
856
857 QVERIFY(file.isOpen());
858 QCOMPARE(file.size(), qint64(0));
859 QCOMPARE(file.pos(), qint64(0));
860
861 fileSize = readContent.size();
862 QCOMPARE(file.write(readContent), fileSize);
863 QCOMPARE(file.pos(), fileSize);
864 QCOMPARE(file.size(), fileSize);
865
866 file.close();
867 QVERIFY(!file.isOpen());
868 QCOMPARE(file.size(), fileSize);
869 }
870
871 //
872 // File content is: readContent
873 //
874}
875
876void tst_QAbstractFileEngine::mounting_data()
877{
878 QTest::addColumn<QString>(name: "fileName");
879 QTest::newRow(dataTag: "native") << "test.tar";
880 QTest::newRow(dataTag: "Forced QFSFileEngine") << "QFSFileEngine:test.tar";
881}
882
883void tst_QAbstractFileEngine::mounting()
884{
885 FileSystem fs;
886 QVERIFY(fs.createFile("test.tar"));
887 FileEngineHandler handler;
888
889 QFETCH(QString, fileName);
890 const QString absName = fs.absoluteFilePath(fileName);
891
892 QVERIFY(QFileInfo(absName).isDir());
893 QDir dir(absName);
894 QCOMPARE(dir.entryList(), (QStringList() << "bar" << "foo"));
895 QDir dir2(fs.path());
896 bool found = false;
897 foreach (QFileInfo info, dir2.entryInfoList()) {
898 if (info.fileName() == QLatin1String("test.tar")) {
899 QVERIFY(!found);
900 found = true;
901 QVERIFY(info.isDir());
902 }
903 }
904 QVERIFY(found);
905}
906
907QTEST_APPLESS_MAIN(tst_QAbstractFileEngine)
908#include "tst_qabstractfileengine.moc"
909
910

source code of qtbase/tests/auto/corelib/io/qabstractfileengine/tst_qabstractfileengine.cpp