| 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 test suite 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 |  | 
| 30 | #include <emulationdetector.h> | 
| 31 | #include <QtTest/QtTest> | 
| 32 | #ifdef QT_BUILD_INTERNAL | 
| 33 | #include <private/qfilesystemmodel_p.h> | 
| 34 | #endif | 
| 35 | #include <QFileSystemModel> | 
| 36 | #include <QFileIconProvider> | 
| 37 | #include <QTreeView> | 
| 38 | #include <QHeaderView> | 
| 39 | #include <QStandardPaths> | 
| 40 | #include <QTime> | 
| 41 | #include <QStyle> | 
| 42 | #include <QtGlobal> | 
| 43 | #include <QTemporaryDir> | 
| 44 | #if defined(Q_OS_WIN) | 
| 45 | # include <qt_windows.h> // for SetFileAttributes | 
| 46 | #endif | 
| 47 | #include <private/qfilesystemengine_p.h> | 
| 48 |  | 
| 49 | #include <algorithm> | 
| 50 |  | 
| 51 | #define WAITTIME 1000 | 
| 52 |  | 
| 53 | // Will try to wait for the condition while allowing event processing | 
| 54 | // for a maximum of 5 seconds. | 
| 55 | #define TRY_WAIT(expr, timedOut) \ | 
| 56 |     do { \ | 
| 57 |         *timedOut = true; \ | 
| 58 |         const int step = 50; \ | 
| 59 |         for (int __i = 0; __i < 5000; __i += step) { \ | 
| 60 |             if (expr) { \ | 
| 61 |                 *timedOut = false; \ | 
| 62 |                 break; \ | 
| 63 |             } \ | 
| 64 |             QTest::qWait(step); \ | 
| 65 |         } \ | 
| 66 |     } while(0) | 
| 67 |  | 
| 68 | Q_DECLARE_METATYPE(QDir::Filters) | 
| 69 | Q_DECLARE_METATYPE(QFileDevice::Permissions) | 
| 70 |  | 
| 71 | Q_LOGGING_CATEGORY(lcFileSystemModel, "qt.widgets.tests.qfilesystemmodel" ) | 
| 72 |  | 
| 73 | class tst_QFileSystemModel : public QObject { | 
| 74 |   Q_OBJECT | 
| 75 |  | 
| 76 | private slots: | 
| 77 |     void initTestCase(); | 
| 78 |     void cleanup(); | 
| 79 |  | 
| 80 |     void indexPath(); | 
| 81 |  | 
| 82 |     void rootPath(); | 
| 83 |     void readOnly(); | 
| 84 |     void iconProvider(); | 
| 85 |  | 
| 86 |     void rowCount(); | 
| 87 |  | 
| 88 |     void rowsInserted_data(); | 
| 89 |     void rowsInserted(); | 
| 90 |  | 
| 91 |     void rowsRemoved_data(); | 
| 92 |     void rowsRemoved(); | 
| 93 |  | 
| 94 |     void dataChanged_data(); | 
| 95 |     void dataChanged(); | 
| 96 |  | 
| 97 |     void filters_data(); | 
| 98 |     void filters(); | 
| 99 |  | 
| 100 |     void nameFilters(); | 
| 101 |  | 
| 102 |     void setData_data(); | 
| 103 |     void setData(); | 
| 104 |  | 
| 105 |     void sortPersistentIndex(); | 
| 106 |     void sort_data(); | 
| 107 |     void sort(); | 
| 108 |  | 
| 109 |     void mkdir(); | 
| 110 |     void deleteFile(); | 
| 111 |     void deleteDirectory(); | 
| 112 |  | 
| 113 |     void caseSensitivity(); | 
| 114 |  | 
| 115 |     void drives_data(); | 
| 116 |     void drives(); | 
| 117 |     void dirsBeforeFiles(); | 
| 118 |  | 
| 119 |     void roleNames_data(); | 
| 120 |     void roleNames(); | 
| 121 |  | 
| 122 |     void permissions_data(); | 
| 123 |     void permissions(); | 
| 124 |  | 
| 125 |     void doNotUnwatchOnFailedRmdir(); | 
| 126 |     void specialFiles(); | 
| 127 |  | 
| 128 |     void fileInfo(); | 
| 129 |  | 
| 130 | protected: | 
| 131 |     bool createFiles(QFileSystemModel *model, const QString &test_path, | 
| 132 |                      const QStringList &initial_files, int existingFileCount = 0, | 
| 133 |                      const QStringList &initial_dirs = QStringList()); | 
| 134 |     QModelIndex prepareTestModelRoot(QFileSystemModel *model, const QString &test_path, | 
| 135 |                                      QSignalSpy **spy2 = nullptr, QSignalSpy **spy3 = nullptr); | 
| 136 |  | 
| 137 | private: | 
| 138 |     QString flatDirTestPath; | 
| 139 |     QTemporaryDir m_tempDir; | 
| 140 | }; | 
| 141 |  | 
| 142 | void tst_QFileSystemModel::cleanup() | 
| 143 | { | 
| 144 |     QDir dir(flatDirTestPath); | 
| 145 |     if (dir.exists()) { | 
| 146 |         const QDir::Filters filters = QDir::AllEntries | QDir::System | QDir::Hidden | QDir::NoDotAndDotDot; | 
| 147 |         const QFileInfoList list = dir.entryInfoList(filters); | 
| 148 |         for (const QFileInfo &fi : list) { | 
| 149 |             if (fi.isDir()) { | 
| 150 |                 QVERIFY(dir.rmdir(fi.fileName())); | 
| 151 |             } else { | 
| 152 |                 QFile dead(fi.absoluteFilePath()); | 
| 153 |                 dead.setPermissions(QFile::ReadUser | QFile::ReadOwner | QFile::ExeOwner | QFile::ExeUser | QFile::WriteUser | QFile::WriteOwner | QFile::WriteOther); | 
| 154 |                 QVERIFY(dead.remove()); | 
| 155 |             } | 
| 156 |         } | 
| 157 |         QVERIFY(dir.entryInfoList(filters).isEmpty()); | 
| 158 |     } | 
| 159 | } | 
| 160 |  | 
| 161 | void tst_QFileSystemModel::initTestCase() | 
| 162 | { | 
| 163 |     QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString())); | 
| 164 |     flatDirTestPath = m_tempDir.path(); | 
| 165 | } | 
| 166 |  | 
| 167 | void tst_QFileSystemModel::indexPath() | 
| 168 | { | 
| 169 | #if !defined(Q_OS_WIN) | 
| 170 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 171 |     int depth = QDir::currentPath().count(c: '/'); | 
| 172 |     model->setRootPath(QDir::currentPath()); | 
| 173 |     QString backPath; | 
| 174 |     for (int i = 0; i <= depth * 2 + 1; ++i) { | 
| 175 |         backPath += "../" ; | 
| 176 |         QModelIndex idx = model->index(path: backPath); | 
| 177 |         QVERIFY(i != depth - 1 ? idx.isValid() : !idx.isValid()); | 
| 178 |     } | 
| 179 | #endif | 
| 180 | } | 
| 181 |  | 
| 182 | void tst_QFileSystemModel::rootPath() | 
| 183 | { | 
| 184 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 185 |     QCOMPARE(model->rootPath(), QString(QDir().path())); | 
| 186 |  | 
| 187 |     QSignalSpy rootChanged(model.data(), &QFileSystemModel::rootPathChanged); | 
| 188 |     QModelIndex root = model->setRootPath(model->rootPath()); | 
| 189 |     root = model->setRootPath("this directory shouldn't exist" ); | 
| 190 |     QCOMPARE(rootChanged.count(), 0); | 
| 191 |  | 
| 192 |     QString oldRootPath = model->rootPath(); | 
| 193 |     const QStringList documentPaths = QStandardPaths::standardLocations(type: QStandardPaths::DocumentsLocation); | 
| 194 |     QVERIFY(!documentPaths.isEmpty()); | 
| 195 |     QString documentPath = documentPaths.front(); | 
| 196 |     // In particular on Linux, ~/Documents (the first | 
| 197 |     // DocumentsLocation) may not exist, so choose ~ in that case: | 
| 198 |     if (!QFile::exists(fileName: documentPath)) { | 
| 199 |         documentPath = QDir::homePath(); | 
| 200 |         qWarning(msg: "%s: first documentPath \"%s\" does not exist. Using ~ (\"%s\") instead." , | 
| 201 |                  Q_FUNC_INFO, qPrintable(documentPaths.front()), qPrintable(documentPath)); | 
| 202 |     } | 
| 203 |     root = model->setRootPath(documentPath); | 
| 204 |  | 
| 205 |     QTRY_VERIFY(model->rowCount(root) >= 0); | 
| 206 |     QCOMPARE(model->rootPath(), QString(documentPath)); | 
| 207 |     QCOMPARE(rootChanged.count(), oldRootPath == model->rootPath() ? 0 : 1); | 
| 208 |     QCOMPARE(model->rootDirectory().absolutePath(), documentPath); | 
| 209 |  | 
| 210 |     model->setRootPath(QDir::rootPath()); | 
| 211 |     int oldCount = rootChanged.count(); | 
| 212 |     oldRootPath = model->rootPath(); | 
| 213 |     root = model->setRootPath(documentPath + QLatin1String("/." )); | 
| 214 |     QTRY_VERIFY(model->rowCount(root) >= 0); | 
| 215 |     QCOMPARE(model->rootPath(), documentPath); | 
| 216 |     QCOMPARE(rootChanged.count(), oldRootPath == model->rootPath() ? oldCount : oldCount + 1); | 
| 217 |     QCOMPARE(model->rootDirectory().absolutePath(), documentPath); | 
| 218 |  | 
| 219 |     QDir newdir = documentPath; | 
| 220 |     if (newdir.cdUp()) { | 
| 221 |         oldCount = rootChanged.count(); | 
| 222 |         oldRootPath = model->rootPath(); | 
| 223 |         root = model->setRootPath(documentPath + QLatin1String("/.." )); | 
| 224 |         QTRY_VERIFY(model->rowCount(root) >= 0); | 
| 225 |         QCOMPARE(model->rootPath(), newdir.path()); | 
| 226 |         QCOMPARE(rootChanged.count(), oldCount + 1); | 
| 227 |         QCOMPARE(model->rootDirectory().absolutePath(), newdir.path()); | 
| 228 |     } | 
| 229 |  | 
| 230 | #ifdef Q_OS_WIN | 
| 231 |     // check case insensitive root node on windows, tests QTBUG-71701 | 
| 232 |     QModelIndex index = model->setRootPath(QString("\\\\localhost\\c$" )); | 
| 233 |     QVERIFY(index.isValid()); | 
| 234 |     QCOMPARE(model->rootPath(), QString("//localhost/c$" )); | 
| 235 |  | 
| 236 |     index = model->setRootPath(QString("\\\\localhost\\C$" )); | 
| 237 |     QVERIFY(index.isValid()); | 
| 238 |     QCOMPARE(model->rootPath(), QString("//localhost/C$" )); | 
| 239 |  | 
| 240 |     index = model->setRootPath(QString("\\\\LOCALHOST\\C$" )); | 
| 241 |     QVERIFY(index.isValid()); | 
| 242 |     QCOMPARE(model->rootPath(), QString("//LOCALHOST/C$" )); | 
| 243 | #endif | 
| 244 | } | 
| 245 |  | 
| 246 | void tst_QFileSystemModel::readOnly() | 
| 247 | { | 
| 248 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 249 |     QCOMPARE(model->isReadOnly(), true); | 
| 250 |     QTemporaryFile file(flatDirTestPath + QStringLiteral("/XXXXXX.dat" )); | 
| 251 |     QVERIFY2(file.open(), qPrintable(file.errorString())); | 
| 252 |     const QString fileName = file.fileName(); | 
| 253 |     file.close(); | 
| 254 |  | 
| 255 |     const QFileInfo fileInfo(fileName); | 
| 256 |     QTRY_VERIFY(QDir(flatDirTestPath).entryInfoList().contains(fileInfo)); | 
| 257 |     QModelIndex root = model->setRootPath(flatDirTestPath); | 
| 258 |  | 
| 259 |     QTRY_VERIFY(model->rowCount(root) > 0); | 
| 260 |     QVERIFY(!(model->flags(model->index(fileName)) & Qt::ItemIsEditable)); | 
| 261 |     model->setReadOnly(false); | 
| 262 |     QCOMPARE(model->isReadOnly(), false); | 
| 263 |     QVERIFY(model->flags(model->index(fileName)) & Qt::ItemIsEditable); | 
| 264 | } | 
| 265 |  | 
| 266 | class CustomFileIconProvider : public QFileIconProvider | 
| 267 | { | 
| 268 | public: | 
| 269 |     CustomFileIconProvider() : QFileIconProvider() | 
| 270 |     { | 
| 271 |         auto style = QApplication::style(); | 
| 272 |         mb = style->standardIcon(standardIcon: QStyle::SP_MessageBoxCritical); | 
| 273 |         dvd = style->standardIcon(standardIcon: QStyle::SP_DriveDVDIcon); | 
| 274 |     } | 
| 275 |  | 
| 276 |     QIcon icon(const QFileInfo &info) const override | 
| 277 |     { | 
| 278 |         if (info.isDir()) | 
| 279 |             return mb; | 
| 280 |  | 
| 281 |         return QFileIconProvider::icon(info); | 
| 282 |     } | 
| 283 |     QIcon icon(IconType type) const override | 
| 284 |     { | 
| 285 |         if (type == QFileIconProvider::Folder) | 
| 286 |             return dvd; | 
| 287 |  | 
| 288 |         return QFileIconProvider::icon(type); | 
| 289 |     } | 
| 290 | private: | 
| 291 |     QIcon mb; | 
| 292 |     QIcon dvd; | 
| 293 | }; | 
| 294 |  | 
| 295 | void tst_QFileSystemModel::iconProvider() | 
| 296 | { | 
| 297 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 298 |     QVERIFY(model->iconProvider()); | 
| 299 |     QScopedPointer<QFileIconProvider> provider(new QFileIconProvider); | 
| 300 |     model->setIconProvider(provider.data()); | 
| 301 |     QCOMPARE(model->iconProvider(), provider.data()); | 
| 302 |     model->setIconProvider(nullptr); | 
| 303 |     provider.reset(); | 
| 304 |  | 
| 305 |     QScopedPointer<QFileSystemModel> myModel(new QFileSystemModel); | 
| 306 |     const QStringList documentPaths = QStandardPaths::standardLocations(type: QStandardPaths::DocumentsLocation); | 
| 307 |     QVERIFY(!documentPaths.isEmpty()); | 
| 308 |     myModel->setRootPath(documentPaths.constFirst()); | 
| 309 |     //We change the provider, icons must be updated | 
| 310 |     provider.reset(other: new CustomFileIconProvider); | 
| 311 |     myModel->setIconProvider(provider.data()); | 
| 312 |  | 
| 313 |     QPixmap mb = QApplication::style()->standardIcon(standardIcon: QStyle::SP_MessageBoxCritical).pixmap(w: 50, h: 50); | 
| 314 |     QCOMPARE(myModel->fileIcon(myModel->index(QDir::homePath())).pixmap(50, 50), mb); | 
| 315 | } | 
| 316 |  | 
| 317 | bool tst_QFileSystemModel::createFiles(QFileSystemModel *model, const QString &test_path, | 
| 318 |                                        const QStringList &initial_files, int existingFileCount, | 
| 319 |                                        const QStringList &initial_dirs) | 
| 320 | { | 
| 321 |     qCDebug(lcFileSystemModel) << (model->rowCount(parent: model->index(path: test_path))) << existingFileCount << initial_files; | 
| 322 |     bool timedOut = false; | 
| 323 |     TRY_WAIT((model->rowCount(model->index(test_path)) == existingFileCount), &timedOut); | 
| 324 |     if (timedOut) | 
| 325 |         return false; | 
| 326 |  | 
| 327 |     QDir dir(test_path); | 
| 328 |     if (!dir.exists()) { | 
| 329 |         qWarning() << "error"  << test_path << "doesn't exist" ; | 
| 330 |         return false; | 
| 331 |     } | 
| 332 |     for (const auto &initial_dir : initial_dirs) { | 
| 333 |         if (!dir.mkdir(dirName: initial_dir)) { | 
| 334 |             qWarning() << "error"  << "failed to make"  << initial_dir; | 
| 335 |             return false; | 
| 336 |         } | 
| 337 |         qCDebug(lcFileSystemModel) << test_path + '/' + initial_dir << (QFile::exists(fileName: test_path + '/' + initial_dir)); | 
| 338 |     } | 
| 339 |     for (const auto &initial_file : initial_files) { | 
| 340 |         QFile file(test_path + '/' + initial_file); | 
| 341 |         if (!file.open(flags: QIODevice::WriteOnly | QIODevice::Append)) { | 
| 342 |             qDebug() << "failed to open file"  << initial_file; | 
| 343 |             return false; | 
| 344 |         } | 
| 345 |         if (!file.resize(sz: 1024 + file.size())) { | 
| 346 |             qDebug() << "failed to resize file"  << initial_file; | 
| 347 |             return false; | 
| 348 |         } | 
| 349 |         if (!file.flush()) { | 
| 350 |             qDebug() << "failed to flush file"  << initial_file; | 
| 351 |             return false; | 
| 352 |         } | 
| 353 |         file.close(); | 
| 354 | #if defined(Q_OS_WIN) | 
| 355 |         if (initial_file[0] == '.') { | 
| 356 |             const QString hiddenFile = QDir::toNativeSeparators(file.fileName()); | 
| 357 |             const auto nativeHiddenFile = reinterpret_cast<const wchar_t *>(hiddenFile.utf16()); | 
| 358 | #ifndef Q_OS_WINRT | 
| 359 |             DWORD currentAttributes = ::GetFileAttributes(nativeHiddenFile); | 
| 360 | #else // !Q_OS_WINRT | 
| 361 |             WIN32_FILE_ATTRIBUTE_DATA attributeData; | 
| 362 |             if (!::GetFileAttributesEx(nativeHiddenFile, GetFileExInfoStandard, &attributeData)) | 
| 363 |                 attributeData.dwFileAttributes = 0xFFFFFFFF; | 
| 364 |             DWORD currentAttributes = attributeData.dwFileAttributes; | 
| 365 | #endif // Q_OS_WINRT | 
| 366 |             if (currentAttributes == 0xFFFFFFFF) { | 
| 367 |                 qErrnoWarning("failed to get file attributes: %s" , qPrintable(hiddenFile)); | 
| 368 |                 return false; | 
| 369 |             } | 
| 370 |             if (!::SetFileAttributes(nativeHiddenFile, currentAttributes | FILE_ATTRIBUTE_HIDDEN)) { | 
| 371 |                 qErrnoWarning("failed to set file hidden: %s" , qPrintable(hiddenFile)); | 
| 372 |                 return false; | 
| 373 |             } | 
| 374 |         } | 
| 375 | #endif | 
| 376 |         qCDebug(lcFileSystemModel) << test_path + '/' + initial_file << (QFile::exists(fileName: test_path + '/' + initial_file)); | 
| 377 |     } | 
| 378 |     return true; | 
| 379 | } | 
| 380 |  | 
| 381 | QModelIndex tst_QFileSystemModel::prepareTestModelRoot(QFileSystemModel *model, const QString &test_path, | 
| 382 |                                                        QSignalSpy **spy2, QSignalSpy **spy3) | 
| 383 | { | 
| 384 |     if (model->rowCount(parent: model->index(path: test_path)) != 0) | 
| 385 |         return QModelIndex(); | 
| 386 |  | 
| 387 |     if (spy2) | 
| 388 |         *spy2 = new QSignalSpy(model, &QFileSystemModel::rowsInserted); | 
| 389 |     if (spy3) | 
| 390 |         *spy3 = new QSignalSpy(model, &QFileSystemModel::rowsAboutToBeInserted); | 
| 391 |  | 
| 392 |     QStringList files = { "b" , "d" , "f" , "h" , "j" , ".a" , ".c" , ".e" , ".g"  }; | 
| 393 |  | 
| 394 |     if (!createFiles(model, test_path, initial_files: files)) | 
| 395 |         return QModelIndex(); | 
| 396 |  | 
| 397 |     QModelIndex root = model->setRootPath(test_path); | 
| 398 |     if (!root.isValid()) | 
| 399 |         return QModelIndex(); | 
| 400 |  | 
| 401 |     bool timedOut = false; | 
| 402 |     TRY_WAIT(model->rowCount(root) == 5, &timedOut); | 
| 403 |     if (timedOut) | 
| 404 |         return QModelIndex(); | 
| 405 |  | 
| 406 |     return root; | 
| 407 | } | 
| 408 |  | 
| 409 | void tst_QFileSystemModel::rowCount() | 
| 410 | { | 
| 411 |     QSignalSpy *spy2 = nullptr; | 
| 412 |     QSignalSpy *spy3 = nullptr; | 
| 413 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 414 |     QModelIndex root = prepareTestModelRoot(model: model.data(), test_path: flatDirTestPath, spy2: &spy2, spy3: &spy3); | 
| 415 |     QVERIFY(root.isValid()); | 
| 416 |  | 
| 417 |     QVERIFY(spy2 && spy2->count() > 0); | 
| 418 |     QVERIFY(spy3 && spy3->count() > 0); | 
| 419 | } | 
| 420 |  | 
| 421 | void tst_QFileSystemModel::rowsInserted_data() | 
| 422 | { | 
| 423 |     QTest::addColumn<int>(name: "count" ); | 
| 424 |     QTest::addColumn<Qt::SortOrder>(name: "ascending" ); | 
| 425 |     for (int i = 0; i < 4; ++i) { | 
| 426 |         const QByteArray iB = QByteArray::number(i); | 
| 427 |         QTest::newRow(dataTag: ("Qt::AscendingOrder "  + iB).constData()) << i << Qt::AscendingOrder; | 
| 428 |         QTest::newRow(dataTag: ("Qt::DescendingOrder "  + iB).constData()) << i << Qt::DescendingOrder; | 
| 429 |     } | 
| 430 | } | 
| 431 |  | 
| 432 | static inline QString lastEntry(const QModelIndex &root) | 
| 433 | { | 
| 434 |     const QAbstractItemModel *model = root.model(); | 
| 435 |     return model->index(row: model->rowCount(parent: root) - 1, column: 0, parent: root).data().toString(); | 
| 436 | } | 
| 437 |  | 
| 438 | void tst_QFileSystemModel::rowsInserted() | 
| 439 | { | 
| 440 |     const QString tmp = flatDirTestPath; | 
| 441 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 442 |     QModelIndex root = prepareTestModelRoot(model: model.data(), test_path: tmp); | 
| 443 |     QVERIFY(root.isValid()); | 
| 444 |  | 
| 445 |     QFETCH(Qt::SortOrder, ascending); | 
| 446 |     QFETCH(int, count); | 
| 447 |     model->sort(column: 0, order: ascending); | 
| 448 |  | 
| 449 |     QSignalSpy spy0(model.data(), &QAbstractItemModel::rowsInserted); | 
| 450 |     QSignalSpy spy1(model.data(), &QAbstractItemModel::rowsAboutToBeInserted); | 
| 451 |     int oldCount = model->rowCount(parent: root); | 
| 452 |     QStringList files; | 
| 453 |     for (int i = 0; i < count; ++i) | 
| 454 |         files.append(t: QLatin1Char('c') + QString::number(i)); | 
| 455 |     QVERIFY(createFiles(model.data(), tmp, files, 5)); | 
| 456 |     QTRY_COMPARE(model->rowCount(root), oldCount + count); | 
| 457 |     int totalRowsInserted = 0; | 
| 458 |     for (int i = 0; i < spy0.count(); ++i) { | 
| 459 |         int start = spy0[i].value(i: 1).toInt(); | 
| 460 |         int end = spy0[i].value(i: 2).toInt(); | 
| 461 |         totalRowsInserted += end - start + 1; | 
| 462 |     } | 
| 463 |     QCOMPARE(totalRowsInserted, count); | 
| 464 |     const QString expected = ascending == Qt::AscendingOrder ? QStringLiteral("j" ) : QStringLiteral("b" ); | 
| 465 |     QTRY_COMPARE(lastEntry(root), expected); | 
| 466 |  | 
| 467 |     if (spy0.count() > 0) { | 
| 468 |         if (count == 0) | 
| 469 |             QCOMPARE(spy0.count(), 0); | 
| 470 |         else | 
| 471 |             QVERIFY(spy0.count() >= 1); | 
| 472 |     } | 
| 473 |     if (count == 0) QCOMPARE(spy1.count(), 0); else QVERIFY(spy1.count() >= 1); | 
| 474 |  | 
| 475 |     QVERIFY(createFiles(model.data(), tmp, QStringList(".hidden_file" ), 5 + count)); | 
| 476 |  | 
| 477 |     if (count != 0) | 
| 478 |         QTRY_VERIFY(spy0.count() >= 1); | 
| 479 |     else | 
| 480 |         QTRY_COMPARE(spy0.count(), 0); | 
| 481 |     if (count != 0) | 
| 482 |         QTRY_VERIFY(spy1.count() >= 1); | 
| 483 |     else | 
| 484 |         QTRY_COMPARE(spy1.count(), 0); | 
| 485 | } | 
| 486 |  | 
| 487 | void tst_QFileSystemModel::rowsRemoved_data() | 
| 488 | { | 
| 489 |     rowsInserted_data(); | 
| 490 | } | 
| 491 |  | 
| 492 | void tst_QFileSystemModel::rowsRemoved() | 
| 493 | { | 
| 494 |     const QString tmp = flatDirTestPath; | 
| 495 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 496 |     QModelIndex root = prepareTestModelRoot(model: model.data(), test_path: tmp); | 
| 497 |     QVERIFY(root.isValid()); | 
| 498 |  | 
| 499 |     QFETCH(int, count); | 
| 500 |     QFETCH(Qt::SortOrder, ascending); | 
| 501 |     model->sort(column: 0, order: ascending); | 
| 502 |  | 
| 503 |     QSignalSpy spy0(model.data(), &QAbstractItemModel::rowsRemoved); | 
| 504 |     QSignalSpy spy1(model.data(), &QAbstractItemModel::rowsAboutToBeRemoved); | 
| 505 |     int oldCount = model->rowCount(parent: root); | 
| 506 |     for (int i = count - 1; i >= 0; --i) { | 
| 507 |         const QString fileName = model->index(row: i, column: 0, parent: root).data().toString(); | 
| 508 |         qCDebug(lcFileSystemModel) << "removing"  << fileName; | 
| 509 |         QVERIFY(QFile::remove(tmp + QLatin1Char('/') + fileName)); | 
| 510 |     } | 
| 511 |     for (int i = 0 ; i < 10; ++i) { | 
| 512 |         if (count != 0) { | 
| 513 |             if (i == 10 || spy0.count() != 0) { | 
| 514 |                 QVERIFY(spy0.count() >= 1); | 
| 515 |                 QVERIFY(spy1.count() >= 1); | 
| 516 |             } | 
| 517 |         } else { | 
| 518 |             if (i == 10 || spy0.count() == 0) { | 
| 519 |                 QCOMPARE(spy0.count(), 0); | 
| 520 |                 QCOMPARE(spy1.count(), 0); | 
| 521 |             } | 
| 522 |         } | 
| 523 |         QStringList lst; | 
| 524 |         for (int i = 0; i < model->rowCount(parent: root); ++i) | 
| 525 |             lst.append(t: model->index(row: i, column: 0, parent: root).data().toString()); | 
| 526 |         if (model->rowCount(parent: root) == oldCount - count) | 
| 527 |             break; | 
| 528 |         qCDebug(lcFileSystemModel) << "still have:"  << lst << QFile::exists(fileName: tmp + QLatin1String("/.a" )); | 
| 529 |         QDir tmpLister(tmp); | 
| 530 |         qCDebug(lcFileSystemModel) << tmpLister.entryList(); | 
| 531 |     } | 
| 532 |     QTRY_COMPARE(model->rowCount(root), oldCount - count); | 
| 533 |  | 
| 534 |     QVERIFY(QFile::exists(tmp + QLatin1String("/.a" ))); | 
| 535 |     QVERIFY(QFile::remove(tmp + QLatin1String("/.a" ))); | 
| 536 |     QVERIFY(QFile::remove(tmp + QLatin1String("/.c" ))); | 
| 537 |  | 
| 538 |     if (count != 0) { | 
| 539 |         QVERIFY(spy0.count() >= 1); | 
| 540 |         QVERIFY(spy1.count() >= 1); | 
| 541 |     } else { | 
| 542 |         QCOMPARE(spy0.count(), 0); | 
| 543 |         QCOMPARE(spy1.count(), 0); | 
| 544 |     } | 
| 545 | } | 
| 546 |  | 
| 547 | void tst_QFileSystemModel::dataChanged_data() | 
| 548 | { | 
| 549 |     rowsInserted_data(); | 
| 550 | } | 
| 551 |  | 
| 552 | void tst_QFileSystemModel::dataChanged() | 
| 553 | { | 
| 554 |     QSKIP("This can't be tested right now since we don't watch files, only directories." ); | 
| 555 |  | 
| 556 |     const QString tmp = flatDirTestPath; | 
| 557 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 558 |     QModelIndex root = prepareTestModelRoot(model: model.data(), test_path: tmp); | 
| 559 |     QVERIFY(root.isValid()); | 
| 560 |  | 
| 561 |     QFETCH(int, count); | 
| 562 |     QFETCH(Qt::SortOrder, ascending); | 
| 563 |     model->sort(column: 0, order: ascending); | 
| 564 |  | 
| 565 |     QSignalSpy spy(model.data(), &QAbstractItemModel::dataChanged); | 
| 566 |     QStringList files; | 
| 567 |     for (int i = 0; i < count; ++i) | 
| 568 |         files.append(t: model->index(row: i, column: 0, parent: root).data().toString()); | 
| 569 |     createFiles(model: model.data(), test_path: tmp, initial_files: files); | 
| 570 |  | 
| 571 |     QTest::qWait(WAITTIME); | 
| 572 |  | 
| 573 |     if (count != 0) QVERIFY(spy.count() >= 1); else QCOMPARE(spy.count(), 0); | 
| 574 | } | 
| 575 |  | 
| 576 | void tst_QFileSystemModel::filters_data() | 
| 577 | { | 
| 578 |     QTest::addColumn<QStringList>(name: "files" ); | 
| 579 |     QTest::addColumn<QStringList>(name: "dirs" ); | 
| 580 |     QTest::addColumn<QDir::Filters>(name: "dirFilters" ); | 
| 581 |     QTest::addColumn<QStringList>(name: "nameFilters" ); | 
| 582 |     QTest::addColumn<int>(name: "rowCount" ); | 
| 583 |  | 
| 584 |     const QStringList abcList{QLatin1String("a" ), QLatin1String("b" ), QLatin1String("c" )}; | 
| 585 |     const QStringList zList{QLatin1String("Z" )}; | 
| 586 |  | 
| 587 |     QTest::newRow(dataTag: "no dirs" ) << abcList << QStringList() << QDir::Filters(QDir::Dirs) << QStringList() << 2; | 
| 588 |     QTest::newRow(dataTag: "no dirs - dot" ) << abcList << QStringList() << (QDir::Dirs | QDir::NoDot) << QStringList() << 1; | 
| 589 |     QTest::newRow(dataTag: "no dirs - dotdot" ) << abcList << QStringList() << (QDir::Dirs | QDir::NoDotDot) << QStringList() << 1; | 
| 590 |     QTest::newRow(dataTag: "no dirs - dotanddotdot" ) << abcList << QStringList() << (QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 0; | 
| 591 |     QTest::newRow(dataTag: "one dir - dot" ) << abcList << zList << (QDir::Dirs | QDir::NoDot) << QStringList() << 2; | 
| 592 |     QTest::newRow(dataTag: "one dir - dotdot" ) << abcList << zList << (QDir::Dirs | QDir::NoDotDot) << QStringList() << 2; | 
| 593 |     QTest::newRow(dataTag: "one dir - dotanddotdot" ) << abcList << zList << (QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; | 
| 594 |     QTest::newRow(dataTag: "one dir" ) << abcList << zList << QDir::Filters(QDir::Dirs) << QStringList() << 3; | 
| 595 |     QTest::newRow(dataTag: "no dir + hidden" ) << abcList << QStringList() << (QDir::Dirs | QDir::Hidden) << QStringList() << 2; | 
| 596 |     QTest::newRow(dataTag: "dir+hid+files" ) << abcList << QStringList() << | 
| 597 |                          (QDir::Dirs | QDir::Files | QDir::Hidden) << QStringList() << 5; | 
| 598 |     QTest::newRow(dataTag: "dir+file+hid-dot .A" ) << abcList << QStringList{QLatin1String(".A" )} << | 
| 599 |                          (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot) << QStringList() << 4; | 
| 600 |     QTest::newRow(dataTag: "dir+files+hid+dot A" ) << abcList << QStringList{QLatin1String("AFolder" )} << | 
| 601 |                          (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot) << QStringList{QLatin1String("A*" )} << 2; | 
| 602 |     QTest::newRow(dataTag: "dir+files+hid+dot+cas1" ) << abcList << zList << | 
| 603 |                          (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive) << zList << 1; | 
| 604 |     QTest::newRow(dataTag: "dir+files+hid+dot+cas2" ) << abcList << zList << | 
| 605 |                          (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive) << QStringList{QLatin1String("a" )} << 1; | 
| 606 |     QTest::newRow(dataTag: "dir+files+hid+dot+cas+alldir" ) << abcList << zList << | 
| 607 |                          (QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::CaseSensitive | QDir::AllDirs) << zList << 1; | 
| 608 |  | 
| 609 |     QTest::newRow(dataTag: "case sensitive" ) << QStringList{QLatin1String("Antiguagdb" ), QLatin1String("Antiguamtd" ), | 
| 610 |         QLatin1String("Antiguamtp" ), QLatin1String("afghanistangdb" ), QLatin1String("afghanistanmtd" )} | 
| 611 |         << QStringList() << QDir::Filters(QDir::Files) << QStringList() << 5; | 
| 612 | } | 
| 613 |  | 
| 614 | void tst_QFileSystemModel::filters() | 
| 615 | { | 
| 616 |     QString tmp = flatDirTestPath; | 
| 617 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 618 |     QVERIFY(createFiles(model.data(), tmp, QStringList())); | 
| 619 |     QModelIndex root = model->setRootPath(tmp); | 
| 620 |     QFETCH(QStringList, files); | 
| 621 |     QFETCH(QStringList, dirs); | 
| 622 |     QFETCH(QDir::Filters, dirFilters); | 
| 623 |     QFETCH(QStringList, nameFilters); | 
| 624 |     QFETCH(int, rowCount); | 
| 625 |  | 
| 626 |     if (nameFilters.count() > 0) | 
| 627 |         model->setNameFilters(nameFilters); | 
| 628 |     model->setNameFilterDisables(false); | 
| 629 |     model->setFilter(dirFilters); | 
| 630 |  | 
| 631 |     QVERIFY(createFiles(model.data(), tmp, files, 0, dirs)); | 
| 632 |     QTRY_COMPARE(model->rowCount(root), rowCount); | 
| 633 |  | 
| 634 |     // Make sure that we do what QDir does | 
| 635 |     QDir xFactor(tmp); | 
| 636 |     QStringList dirEntries; | 
| 637 |  | 
| 638 |     if (nameFilters.count() > 0) | 
| 639 |         dirEntries = xFactor.entryList(nameFilters, filters: dirFilters); | 
| 640 |     else | 
| 641 |         dirEntries = xFactor.entryList(filters: dirFilters); | 
| 642 |  | 
| 643 |     QCOMPARE(dirEntries.count(), rowCount); | 
| 644 |  | 
| 645 |     QStringList modelEntries; | 
| 646 |  | 
| 647 |     for (int i = 0; i < rowCount; ++i) | 
| 648 |         modelEntries.append(t: model->data(index: model->index(row: i, column: 0, parent: root), role: QFileSystemModel::FileNameRole).toString()); | 
| 649 |  | 
| 650 |     std::sort(first: dirEntries.begin(), last: dirEntries.end()); | 
| 651 |     std::sort(first: modelEntries.begin(), last: modelEntries.end()); | 
| 652 |     QCOMPARE(dirEntries, modelEntries); | 
| 653 |  | 
| 654 | #ifdef Q_OS_LINUX | 
| 655 |     if (files.count() >= 3 && rowCount >= 3 && rowCount != 5) { | 
| 656 |         QString fileName1 = (tmp + '/' + files.at(i: 0)); | 
| 657 |         QString fileName2 = (tmp + '/' + files.at(i: 1)); | 
| 658 |         QString fileName3 = (tmp + '/' + files.at(i: 2)); | 
| 659 |         QFile::Permissions originalPermissions = QFile::permissions(filename: fileName1); | 
| 660 |         QVERIFY(QFile::setPermissions(fileName1, QFile::WriteOwner)); | 
| 661 |         QVERIFY(QFile::setPermissions(fileName2, QFile::ReadOwner)); | 
| 662 |         QVERIFY(QFile::setPermissions(fileName3, QFile::ExeOwner)); | 
| 663 |  | 
| 664 |         model->setFilter((QDir::Files | QDir::Readable)); | 
| 665 |         QTRY_COMPARE(model->rowCount(root), 1); | 
| 666 |  | 
| 667 |         model->setFilter((QDir::Files | QDir::Writable)); | 
| 668 |         QTRY_COMPARE(model->rowCount(root), 1); | 
| 669 |  | 
| 670 |         model->setFilter((QDir::Files | QDir::Executable)); | 
| 671 |         QTRY_COMPARE(model->rowCount(root), 1); | 
| 672 |  | 
| 673 |         // reset permissions | 
| 674 |         QVERIFY(QFile::setPermissions(fileName1, originalPermissions)); | 
| 675 |         QVERIFY(QFile::setPermissions(fileName2, originalPermissions)); | 
| 676 |         QVERIFY(QFile::setPermissions(fileName3, originalPermissions)); | 
| 677 |     } | 
| 678 | #endif | 
| 679 | } | 
| 680 |  | 
| 681 | void tst_QFileSystemModel::nameFilters() | 
| 682 | { | 
| 683 |     QStringList list; | 
| 684 |     list << "a"  << "b"  << "c" ; | 
| 685 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 686 |     model->setNameFilters(list); | 
| 687 |     model->setNameFilterDisables(false); | 
| 688 |     QCOMPARE(model->nameFilters(), list); | 
| 689 |  | 
| 690 |     QString tmp = flatDirTestPath; | 
| 691 |     QVERIFY(createFiles(model.data(), tmp, list)); | 
| 692 |     QModelIndex root = model->setRootPath(tmp); | 
| 693 |     QTRY_COMPARE(model->rowCount(root), 3); | 
| 694 |  | 
| 695 |     QStringList filters; | 
| 696 |     filters << "a"  << "b" ; | 
| 697 |     model->setNameFilters(filters); | 
| 698 |     QTRY_COMPARE(model->rowCount(root), 2); | 
| 699 | } | 
| 700 | void tst_QFileSystemModel::setData_data() | 
| 701 | { | 
| 702 |     QTest::addColumn<QString>(name: "subdirName" ); | 
| 703 |     QTest::addColumn<QStringList>(name: "files" ); | 
| 704 |     QTest::addColumn<QString>(name: "oldFileName" ); | 
| 705 |     QTest::addColumn<QString>(name: "newFileName" ); | 
| 706 |     QTest::addColumn<bool>(name: "success" ); | 
| 707 |     /*QTest::newRow("outside current dir") << (QStringList() << "a" << "b" << "c") | 
| 708 |               << flatDirTestPath + '/' + "a" | 
| 709 |               << QDir::temp().absolutePath() + '/' + "a" | 
| 710 |               << false; | 
| 711 |     */ | 
| 712 |  | 
| 713 |     const QStringList abcList{QLatin1String("a" ), QLatin1String("b" ), QLatin1String("c" )}; | 
| 714 |     QTest::newRow(dataTag: "in current dir" ) | 
| 715 |               << QString() | 
| 716 |               << abcList | 
| 717 |               << "a"  | 
| 718 |               << "d"  | 
| 719 |               << true; | 
| 720 |     QTest::newRow(dataTag: "in subdir" ) | 
| 721 |               << "s"  | 
| 722 |               << abcList | 
| 723 |               << "a"  | 
| 724 |               << "d"  | 
| 725 |               << true; | 
| 726 | } | 
| 727 |  | 
| 728 | void tst_QFileSystemModel::setData() | 
| 729 | { | 
| 730 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 731 |     QSignalSpy spy(model.data(), &QFileSystemModel::fileRenamed); | 
| 732 |     QFETCH(QString, subdirName); | 
| 733 |     QFETCH(QStringList, files); | 
| 734 |     QFETCH(QString, oldFileName); | 
| 735 |     QFETCH(QString, newFileName); | 
| 736 |     QFETCH(bool, success); | 
| 737 |  | 
| 738 |     QString tmp = flatDirTestPath; | 
| 739 |     if (!subdirName.isEmpty()) { | 
| 740 |         QDir dir(tmp); | 
| 741 |         QVERIFY(dir.mkdir(subdirName)); | 
| 742 |         tmp.append(s: '/' + subdirName); | 
| 743 |     } | 
| 744 |     QVERIFY(createFiles(model.data(), tmp, files)); | 
| 745 |     QModelIndex tmpIdx = model->setRootPath(flatDirTestPath); | 
| 746 |     if (!subdirName.isEmpty()) { | 
| 747 |         tmpIdx = model->index(path: tmp); | 
| 748 |         model->fetchMore(parent: tmpIdx); | 
| 749 |     } | 
| 750 |     QTRY_COMPARE(model->rowCount(tmpIdx), files.count()); | 
| 751 |  | 
| 752 |     QModelIndex idx = model->index(path: tmp + '/' + oldFileName); | 
| 753 |     QCOMPARE(idx.isValid(), true); | 
| 754 |     QCOMPARE(model->setData(idx, newFileName), false); | 
| 755 |  | 
| 756 |     model->setReadOnly(false); | 
| 757 |     QCOMPARE(model->setData(idx, newFileName), success); | 
| 758 |     model->setReadOnly(true); | 
| 759 |     if (success) { | 
| 760 |         QCOMPARE(spy.count(), 1); | 
| 761 |         QList<QVariant> arguments = spy.takeFirst(); | 
| 762 |         QCOMPARE(model->data(idx, QFileSystemModel::FileNameRole).toString(), newFileName); | 
| 763 |         QCOMPARE(model->fileInfo(idx).filePath(), tmp + '/' + newFileName); | 
| 764 |         QCOMPARE(model->index(arguments.at(0).toString()), model->index(tmp)); | 
| 765 |         QCOMPARE(arguments.at(1).toString(), oldFileName); | 
| 766 |         QCOMPARE(arguments.at(2).toString(), newFileName); | 
| 767 |         QCOMPARE(QFile::rename(tmp + '/' + newFileName, tmp + '/' + oldFileName), true); | 
| 768 |     } | 
| 769 |     QTRY_COMPARE(model->rowCount(tmpIdx), files.count()); | 
| 770 |     // cleanup | 
| 771 |     if (!subdirName.isEmpty()) | 
| 772 |         QVERIFY(QDir(tmp).removeRecursively()); | 
| 773 | } | 
| 774 |  | 
| 775 | void tst_QFileSystemModel::sortPersistentIndex() | 
| 776 | { | 
| 777 |     QTemporaryFile file(flatDirTestPath + QStringLiteral("/XXXXXX.dat" )); | 
| 778 |     QVERIFY2(file.open(), qPrintable(file.errorString())); | 
| 779 |     const QFileInfo fileInfo(file.fileName()); | 
| 780 |     file.close(); | 
| 781 |     QTRY_VERIFY(QDir(flatDirTestPath).entryInfoList().contains(fileInfo)); | 
| 782 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 783 |     QModelIndex root = model->setRootPath(flatDirTestPath); | 
| 784 |     QTRY_VERIFY(model->rowCount(root) > 0); | 
| 785 |  | 
| 786 |     QPersistentModelIndex idx = model->index(row: 0, column: 1, parent: root); | 
| 787 |     model->sort(column: 0, order: Qt::AscendingOrder); | 
| 788 |     model->sort(column: 0, order: Qt::DescendingOrder); | 
| 789 |     QVERIFY(idx.column() != 0); | 
| 790 | } | 
| 791 |  | 
| 792 | class MyFriendFileSystemModel : public QFileSystemModel | 
| 793 | { | 
| 794 |     friend class tst_QFileSystemModel; | 
| 795 |     Q_DECLARE_PRIVATE(QFileSystemModel) | 
| 796 | }; | 
| 797 |  | 
| 798 | void tst_QFileSystemModel::sort_data() | 
| 799 | { | 
| 800 |     QTest::addColumn<bool>(name: "fileDialogMode" ); | 
| 801 |     QTest::newRow(dataTag: "standard usage" ) << false; | 
| 802 |     QTest::newRow(dataTag: "QFileDialog usage" ) << true; | 
| 803 | } | 
| 804 |  | 
| 805 | void tst_QFileSystemModel::sort() | 
| 806 | { | 
| 807 |     QFETCH(bool, fileDialogMode); | 
| 808 |  | 
| 809 |     QScopedPointer<MyFriendFileSystemModel> myModel(new MyFriendFileSystemModel); | 
| 810 |     QTreeView tree; | 
| 811 |     tree.setWindowTitle(QTest::currentTestFunction()); | 
| 812 |  | 
| 813 |     if (fileDialogMode && EmulationDetector::isRunningArmOnX86()) | 
| 814 |         QSKIP("Crashes in QEMU. QTBUG-70572" ); | 
| 815 |  | 
| 816 | #ifdef QT_BUILD_INTERNAL | 
| 817 |     if (fileDialogMode) | 
| 818 |         myModel->d_func()->disableRecursiveSort = true; | 
| 819 | #endif | 
| 820 |  | 
| 821 |     QDir dir(flatDirTestPath); | 
| 822 |     const QString dirPath = dir.absolutePath(); | 
| 823 |  | 
| 824 |     //Create a file that will be at the end when sorting by name (For Mac, the default) | 
| 825 |     //but if we sort by size descending it will be the first | 
| 826 |     QFile tempFile(dirPath + "/plop2.txt" ); | 
| 827 |     tempFile.open(flags: QIODevice::WriteOnly | QIODevice::Text); | 
| 828 |     QTextStream out(&tempFile); | 
| 829 |     out << "The magic number is: "  << 49 << "\n" ; | 
| 830 |     tempFile.close(); | 
| 831 |  | 
| 832 |     QFile tempFile2(dirPath + "/plop.txt" ); | 
| 833 |     tempFile2.open(flags: QIODevice::WriteOnly | QIODevice::Text); | 
| 834 |     QTextStream out2(&tempFile2); | 
| 835 |     out2 << "The magic number is : "  << 49 << " but i write some stuff in the file \n" ; | 
| 836 |     tempFile2.close(); | 
| 837 |  | 
| 838 |     myModel->setRootPath("" ); | 
| 839 |     myModel->setFilter(QDir::AllEntries | QDir::System | QDir::Hidden); | 
| 840 |     tree.setSortingEnabled(true); | 
| 841 |     tree.setModel(myModel.data()); | 
| 842 |     tree.show(); | 
| 843 |     tree.resize(w: 800, h: 800); | 
| 844 |     QVERIFY(QTest::qWaitForWindowExposed(&tree)); | 
| 845 |     tree.header()->setSortIndicator(logicalIndex: 1, order: Qt::DescendingOrder); | 
| 846 |     tree.header()->setSectionResizeMode(logicalIndex: 0, mode: QHeaderView::ResizeToContents); | 
| 847 |     QStringList dirsToOpen; | 
| 848 |     do { | 
| 849 |         dirsToOpen << dir.absolutePath(); | 
| 850 |     } while (dir.cdUp()); | 
| 851 |  | 
| 852 |     for (int i = dirsToOpen.size() -1 ; i > 0 ; --i) { | 
| 853 |         QString path = dirsToOpen[i]; | 
| 854 |         tree.expand(index: myModel->index(path, column: 0)); | 
| 855 |     } | 
| 856 |     tree.expand(index: myModel->index(path: dirPath, column: 0)); | 
| 857 |     QModelIndex parent = myModel->index(path: dirPath, column: 0); | 
| 858 |     QList<QString> expectedOrder; | 
| 859 |     expectedOrder << tempFile2.fileName() << tempFile.fileName() << dirPath + QChar('/') + ".."  << dirPath + QChar('/') + "." ; | 
| 860 |  | 
| 861 |     if (fileDialogMode) { | 
| 862 |         QTRY_COMPARE(myModel->rowCount(parent), expectedOrder.count()); | 
| 863 |         // File dialog Mode means sub trees are not sorted, only the current root. | 
| 864 |         // There's no way we can check that the sub tree is "not sorted"; just check if it | 
| 865 |         // has the same contents of the expected list | 
| 866 |         QList<QString> actualRows; | 
| 867 |         for(int i = 0; i < myModel->rowCount(parent); ++i) | 
| 868 |         { | 
| 869 |             actualRows << dirPath + QChar('/') + myModel->index(row: i, column: 1, parent).data(arole: QFileSystemModel::FileNameRole).toString(); | 
| 870 |         } | 
| 871 |  | 
| 872 |         std::sort(first: expectedOrder.begin(), last: expectedOrder.end()); | 
| 873 |         std::sort(first: actualRows.begin(), last: actualRows.end()); | 
| 874 |  | 
| 875 |         QCOMPARE(actualRows, expectedOrder); | 
| 876 |     } else { | 
| 877 |         for(int i = 0; i < myModel->rowCount(parent); ++i) | 
| 878 |         { | 
| 879 |             QTRY_COMPARE(dirPath + QChar('/') + myModel->index(i, 1, parent).data(QFileSystemModel::FileNameRole).toString(), expectedOrder.at(i)); | 
| 880 |         } | 
| 881 |     } | 
| 882 | } | 
| 883 |  | 
| 884 | void tst_QFileSystemModel::mkdir() | 
| 885 | { | 
| 886 |     QString tmp = flatDirTestPath; | 
| 887 |     QString newFolderPath = QDir::toNativeSeparators(pathName: tmp + '/' + "NewFoldermkdirtest4" ); | 
| 888 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 889 |     QModelIndex tmpDir = model->index(path: tmp); | 
| 890 |     QVERIFY(tmpDir.isValid()); | 
| 891 |     QDir bestatic(newFolderPath); | 
| 892 |     if (bestatic.exists()) { | 
| 893 |         if (!bestatic.rmdir(dirName: newFolderPath)) | 
| 894 |             qWarning() << "unable to remove"  << newFolderPath; | 
| 895 |         QTest::qWait(WAITTIME); | 
| 896 |     } | 
| 897 |     model->mkdir(parent: tmpDir, name: "NewFoldermkdirtest3" ); | 
| 898 |     model->mkdir(parent: tmpDir, name: "NewFoldermkdirtest5" ); | 
| 899 |     QModelIndex idx = model->mkdir(parent: tmpDir, name: "NewFoldermkdirtest4" ); | 
| 900 |     QVERIFY(idx.isValid()); | 
| 901 |     int oldRow = idx.row(); | 
| 902 |     idx = model->index(path: newFolderPath); | 
| 903 |     QVERIFY(idx.isValid()); | 
| 904 |     QVERIFY(model->remove(idx)); | 
| 905 |     QVERIFY(!bestatic.exists()); | 
| 906 |     QVERIFY(0 != idx.row()); | 
| 907 |     QCOMPARE(oldRow, idx.row()); | 
| 908 | } | 
| 909 |  | 
| 910 | void tst_QFileSystemModel::deleteFile() | 
| 911 | { | 
| 912 |     QString newFilePath = QDir::temp().filePath(fileName: "NewFileDeleteTest" ); | 
| 913 |     QFile newFile(newFilePath); | 
| 914 |     if (newFile.exists()) { | 
| 915 |         if (!newFile.remove()) | 
| 916 |             qWarning() << "unable to remove"  << newFilePath; | 
| 917 |         QTest::qWait(WAITTIME); | 
| 918 |     } | 
| 919 |     if (!newFile.open(flags: QIODevice::WriteOnly | QIODevice::Text)) { | 
| 920 |         qWarning() << "unable to create"  << newFilePath; | 
| 921 |     } | 
| 922 |     newFile.close(); | 
| 923 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 924 |     QModelIndex idx = model->index(path: newFilePath); | 
| 925 |     QVERIFY(idx.isValid()); | 
| 926 |     QVERIFY(model->remove(idx)); | 
| 927 |     QVERIFY(!newFile.exists()); | 
| 928 | } | 
| 929 |  | 
| 930 | void tst_QFileSystemModel::deleteDirectory() | 
| 931 | { | 
| 932 |     // QTBUG-65683: Verify that directories can be removed recursively despite | 
| 933 |     // file system watchers being active on them or their sub-directories (Windows). | 
| 934 |     // Create a temporary directory, a nested directory and expand a treeview | 
| 935 |     // to show them to ensure watcher creation. Then delete the directory. | 
| 936 |     QTemporaryDir dirToBeDeleted(flatDirTestPath + QStringLiteral("/deleteDirectory-XXXXXX" )); | 
| 937 |     QVERIFY(dirToBeDeleted.isValid()); | 
| 938 |     const QString dirToBeDeletedPath = dirToBeDeleted.path(); | 
| 939 |     const QString nestedTestDir = QStringLiteral("test" ); | 
| 940 |     QVERIFY(QDir(dirToBeDeletedPath).mkpath(nestedTestDir)); | 
| 941 |     const QString nestedTestDirPath = dirToBeDeletedPath + QLatin1Char('/') + nestedTestDir; | 
| 942 |     QFile testFile(nestedTestDirPath + QStringLiteral("/test.txt" )); | 
| 943 |     QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); | 
| 944 |     testFile.write(data: "Hello\n" ); | 
| 945 |     testFile.close(); | 
| 946 |  | 
| 947 |     QFileSystemModel model; | 
| 948 |     const QModelIndex rootIndex = model.setRootPath(flatDirTestPath); | 
| 949 |     QTreeView treeView; | 
| 950 |     treeView.setWindowTitle(QTest::currentTestFunction()); | 
| 951 |     treeView.setModel(&model); | 
| 952 |     treeView.setRootIndex(rootIndex); | 
| 953 |  | 
| 954 |     const QModelIndex dirToBeDeletedPathIndex = model.index(path: dirToBeDeletedPath); | 
| 955 |     QVERIFY(dirToBeDeletedPathIndex.isValid()); | 
| 956 |     treeView.setExpanded(index: dirToBeDeletedPathIndex, expand: true); | 
| 957 |     const QModelIndex nestedTestDirIndex = model.index(path: nestedTestDirPath); | 
| 958 |     QVERIFY(nestedTestDirIndex.isValid()); | 
| 959 |     treeView.setExpanded(index: nestedTestDirIndex, expand: true); | 
| 960 |  | 
| 961 |     treeView.show(); | 
| 962 |     QVERIFY(QTest::qWaitForWindowExposed(&treeView)); | 
| 963 |  | 
| 964 |     QVERIFY(model.remove(dirToBeDeletedPathIndex)); | 
| 965 |     dirToBeDeleted.setAutoRemove(false); | 
| 966 | } | 
| 967 |  | 
| 968 | static QString flipCase(QString s) | 
| 969 | { | 
| 970 |     for (int i = 0, size = s.size(); i < size; ++i) { | 
| 971 |         const QChar c = s.at(i); | 
| 972 |         if (c.isUpper()) | 
| 973 |             s[i] = c.toLower(); | 
| 974 |         else if (c.isLower()) | 
| 975 |             s[i] = c.toUpper(); | 
| 976 |     } | 
| 977 |     return s; | 
| 978 | } | 
| 979 |  | 
| 980 | void tst_QFileSystemModel::caseSensitivity() | 
| 981 | { | 
| 982 |     QString tmp = flatDirTestPath; | 
| 983 |     QStringList files; | 
| 984 |     files << "a"  << "c"  << "C" ; | 
| 985 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 986 |     QVERIFY(createFiles(model.data(), tmp, files)); | 
| 987 |     QModelIndex root = model->index(path: tmp); | 
| 988 |     QStringList paths; | 
| 989 |     QModelIndexList indexes; | 
| 990 |     QCOMPARE(model->rowCount(root), 0); | 
| 991 |     for (int i = 0; i < files.count(); ++i) { | 
| 992 |         const QString path = tmp + '/' + files.at(i); | 
| 993 |         const QModelIndex index = model->index(path); | 
| 994 |         QVERIFY(index.isValid()); | 
| 995 |         paths.append(t: path); | 
| 996 |         indexes.append(t: index); | 
| 997 |     } | 
| 998 |  | 
| 999 |     if (!QFileSystemEngine::isCaseSensitive()) { | 
| 1000 |         // QTBUG-31103, QTBUG-64147: Verify that files can be accessed by paths with fLipPeD case. | 
| 1001 |         for (int i = 0; i < paths.count(); ++i) { | 
| 1002 |             const QModelIndex flippedCaseIndex = model->index(path: flipCase(s: paths.at(i))); | 
| 1003 |             QCOMPARE(indexes.at(i), flippedCaseIndex); | 
| 1004 |         } | 
| 1005 |     } | 
| 1006 | } | 
| 1007 |  | 
| 1008 | void tst_QFileSystemModel::drives_data() | 
| 1009 | { | 
| 1010 |     QTest::addColumn<QString>(name: "path" ); | 
| 1011 |     QTest::newRow(dataTag: "current" ) << QDir::currentPath(); | 
| 1012 |     QTest::newRow(dataTag: "slash" ) << "/" ; | 
| 1013 |     QTest::newRow(dataTag: "My Computer" ) << "My Computer" ; | 
| 1014 | } | 
| 1015 |  | 
| 1016 | void tst_QFileSystemModel::drives() | 
| 1017 | { | 
| 1018 |     QFETCH(QString, path); | 
| 1019 |     QFileSystemModel model; | 
| 1020 |     model.setRootPath(path); | 
| 1021 |     model.fetchMore(parent: QModelIndex()); | 
| 1022 |     QFileInfoList drives = QDir::drives(); | 
| 1023 |     int driveCount = 0; | 
| 1024 |     foreach(const QFileInfo& driveRoot, drives) | 
| 1025 |         if (driveRoot.exists()) | 
| 1026 |             driveCount++; | 
| 1027 |     QTRY_COMPARE(model.rowCount(), driveCount); | 
| 1028 | } | 
| 1029 |  | 
| 1030 | void tst_QFileSystemModel::dirsBeforeFiles() | 
| 1031 | { | 
| 1032 |     auto diagnosticMsg = [](int row, const QFileInfo &left, const QFileInfo &right) -> QByteArray { | 
| 1033 |         QString message; | 
| 1034 |         QDebug(&message).noquote() << "Unexpected sort order at #"  << row << ':' << left << right; | 
| 1035 |         return message.toLocal8Bit(); | 
| 1036 |     }; | 
| 1037 |     QTemporaryDir testDir(flatDirTestPath); | 
| 1038 |     QVERIFY2(testDir.isValid(), qPrintable(testDir.errorString())); | 
| 1039 |     QDir dir(testDir.path()); | 
| 1040 |  | 
| 1041 |     const int itemCount = 3; | 
| 1042 |     for (int i = 0; i < itemCount; ++i) { | 
| 1043 |         QLatin1Char c('a' + char(i)); | 
| 1044 |         QVERIFY(dir.mkdir(c + QLatin1String("-dir" ))); | 
| 1045 |         QFile file(dir.filePath(fileName: c + QLatin1String("-file" ))); | 
| 1046 |         QVERIFY(file.open(QIODevice::ReadWrite)); | 
| 1047 |         file.close(); | 
| 1048 |     } | 
| 1049 |  | 
| 1050 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 1051 |     QModelIndex root = model->setRootPath(dir.absolutePath()); | 
| 1052 |     // Wait for model to be notified by the file system watcher | 
| 1053 |     QTRY_COMPARE(model->rowCount(root), 2 * itemCount); | 
| 1054 |     // sort explicitly - dirs before files (except on macOS), and then by name | 
| 1055 |     model->sort(column: 0); | 
| 1056 |     // Ensure that no file occurs before any directory (see QFileSystemModelSorter): | 
| 1057 |     for (int i = 1, count = model->rowCount(parent: root); i < count; ++i) { | 
| 1058 |         const QFileInfo previous = model->fileInfo(index: model->index(row: i - 1, column: 0, parent: root)); | 
| 1059 |         const QFileInfo current = model->fileInfo(index: model->index(row: i, column: 0, parent: root)); | 
| 1060 | #ifndef Q_OS_MAC | 
| 1061 |         QVERIFY2(!(previous.isFile() && current.isDir()), diagnosticMsg(i, previous, current).constData()); | 
| 1062 | #else | 
| 1063 |         QVERIFY2(previous.fileName() < current.fileName(), diagnosticMsg(i, previous, current).constData()); | 
| 1064 | #endif | 
| 1065 |     } | 
| 1066 | } | 
| 1067 |  | 
| 1068 | void tst_QFileSystemModel::roleNames_data() | 
| 1069 | { | 
| 1070 |     QTest::addColumn<int>(name: "role" ); | 
| 1071 |     QTest::addColumn<QByteArray>(name: "roleName" ); | 
| 1072 |     QTest::newRow(dataTag: "decoration" ) << int(Qt::DecorationRole) << QByteArray("fileIcon" ); | 
| 1073 |     QTest::newRow(dataTag: "display" ) << int(Qt::DisplayRole) << QByteArray("display" ); | 
| 1074 |     QTest::newRow(dataTag: "fileIcon" ) << int(QFileSystemModel::FileIconRole) << QByteArray("fileIcon" ); | 
| 1075 |     QTest::newRow(dataTag: "filePath" ) << int(QFileSystemModel::FilePathRole) << QByteArray("filePath" ); | 
| 1076 |     QTest::newRow(dataTag: "fileName" ) << int(QFileSystemModel::FileNameRole) << QByteArray("fileName" ); | 
| 1077 |     QTest::newRow(dataTag: "filePermissions" ) << int(QFileSystemModel::FilePermissions) << QByteArray("filePermissions" ); | 
| 1078 | } | 
| 1079 |  | 
| 1080 | void tst_QFileSystemModel::roleNames() | 
| 1081 | { | 
| 1082 |     QFileSystemModel model; | 
| 1083 |     QHash<int, QByteArray> roles = model.roleNames(); | 
| 1084 |  | 
| 1085 |     QFETCH(int, role); | 
| 1086 |     QVERIFY(roles.contains(role)); | 
| 1087 |  | 
| 1088 |     QFETCH(QByteArray, roleName); | 
| 1089 |     QCOMPARE(roles.values(role).count(), 1); | 
| 1090 |     QCOMPARE(roles.value(role), roleName); | 
| 1091 | } | 
| 1092 |  | 
| 1093 | static inline QByteArray permissionRowName(bool readOnly, int permission) | 
| 1094 | { | 
| 1095 |     QByteArray result = readOnly ? QByteArrayLiteral("ro" ) : QByteArrayLiteral("rw" ); | 
| 1096 |     result += QByteArrayLiteral("-0" ); | 
| 1097 |     result += QByteArray::number(permission, base: 16); | 
| 1098 |     return result; | 
| 1099 | } | 
| 1100 |  | 
| 1101 | void tst_QFileSystemModel::permissions_data() | 
| 1102 | { | 
| 1103 |     QTest::addColumn<QFileDevice::Permissions>(name: "permissions" ); | 
| 1104 |     QTest::addColumn<bool>(name: "readOnly" ); | 
| 1105 |  | 
| 1106 |     static const int permissions[] = { | 
| 1107 |         QFile::WriteOwner, | 
| 1108 |         QFile::ReadOwner, | 
| 1109 |         QFile::WriteOwner|QFile::ReadOwner, | 
| 1110 |     }; | 
| 1111 |     for (int permission : permissions) { | 
| 1112 |         QTest::newRow(dataTag: permissionRowName(readOnly: false, permission).constData()) << QFileDevice::Permissions(permission) << false; | 
| 1113 |         QTest::newRow(dataTag: permissionRowName(readOnly: true, permission).constData()) << QFileDevice::Permissions(permission) << true; | 
| 1114 |     } | 
| 1115 | } | 
| 1116 |  | 
| 1117 | void tst_QFileSystemModel::permissions() // checks QTBUG-20503 | 
| 1118 | { | 
| 1119 |     QFETCH(QFileDevice::Permissions, permissions); | 
| 1120 |     QFETCH(bool, readOnly); | 
| 1121 |  | 
| 1122 |     const QString tmp = flatDirTestPath; | 
| 1123 |     const QString file = tmp + QLatin1String("/f" ); | 
| 1124 |     QScopedPointer<QFileSystemModel> model(new QFileSystemModel); | 
| 1125 |     QVERIFY(createFiles(model.data(), tmp, QStringList{QLatin1String("f" )})); | 
| 1126 |  | 
| 1127 |     QVERIFY(QFile::setPermissions(file,  permissions)); | 
| 1128 |  | 
| 1129 |     const QModelIndex root = model->setRootPath(tmp); | 
| 1130 |  | 
| 1131 |     model->setReadOnly(readOnly); | 
| 1132 |  | 
| 1133 |     QCOMPARE(model->isReadOnly(), readOnly); | 
| 1134 |  | 
| 1135 |     QTRY_COMPARE(model->rowCount(root), 1); | 
| 1136 |  | 
| 1137 |     const QFile::Permissions modelPermissions = model->permissions(index: model->index(row: 0, column: 0, parent: root)); | 
| 1138 |     const QFile::Permissions modelFileInfoPermissions = model->fileInfo(index: model->index(row: 0, column: 0, parent: root)).permissions(); | 
| 1139 |     const QFile::Permissions fileInfoPermissions = QFileInfo(file).permissions(); | 
| 1140 |  | 
| 1141 |     QCOMPARE(modelPermissions, modelFileInfoPermissions); | 
| 1142 |     QCOMPARE(modelFileInfoPermissions, fileInfoPermissions); | 
| 1143 |     QCOMPARE(fileInfoPermissions, modelPermissions); | 
| 1144 | } | 
| 1145 |  | 
| 1146 | void tst_QFileSystemModel::doNotUnwatchOnFailedRmdir() | 
| 1147 | { | 
| 1148 |     const QString tmp = flatDirTestPath; | 
| 1149 |  | 
| 1150 |     QFileSystemModel model; | 
| 1151 |  | 
| 1152 |     const QTemporaryDir tempDir(tmp + '/' + QStringLiteral("doNotUnwatchOnFailedRmdir-XXXXXX" )); | 
| 1153 |     QVERIFY(tempDir.isValid()); | 
| 1154 |  | 
| 1155 |     const QModelIndex rootIndex = model.setRootPath(tempDir.path()); | 
| 1156 |  | 
| 1157 |     // create a file in the directory so to prevent it from deletion | 
| 1158 |     { | 
| 1159 |         QFile file(tempDir.path() + '/' + QStringLiteral("file1" )); | 
| 1160 |         QVERIFY(file.open(QIODevice::WriteOnly)); | 
| 1161 |     } | 
| 1162 |  | 
| 1163 |     QCOMPARE(model.rmdir(rootIndex), false); | 
| 1164 |  | 
| 1165 |     // create another file | 
| 1166 |     { | 
| 1167 |         QFile file(tempDir.path() + '/' + QStringLiteral("file2" )); | 
| 1168 |         QVERIFY(file.open(QIODevice::WriteOnly)); | 
| 1169 |     } | 
| 1170 |  | 
| 1171 |     // the model must now detect this second file | 
| 1172 |     QTRY_COMPARE(model.rowCount(rootIndex), 2); | 
| 1173 | } | 
| 1174 |  | 
| 1175 | static QSet<QString> fileListUnderIndex(const QFileSystemModel *model, const QModelIndex &parent) | 
| 1176 | { | 
| 1177 |     QSet<QString> fileNames; | 
| 1178 |     const int rowCount = model->rowCount(parent); | 
| 1179 |     for (int i = 0; i < rowCount; ++i) | 
| 1180 |         fileNames.insert(value: model->index(row: i, column: 0, parent).data(arole: QFileSystemModel::FileNameRole).toString()); | 
| 1181 |     return fileNames; | 
| 1182 | } | 
| 1183 |  | 
| 1184 | void tst_QFileSystemModel::specialFiles() | 
| 1185 | { | 
| 1186 | #ifndef Q_OS_UNIX | 
| 1187 |      QSKIP("Not implemented" ); | 
| 1188 | #endif | 
| 1189 |  | 
| 1190 |     QFileSystemModel model; | 
| 1191 |  | 
| 1192 |     model.setFilter(QDir::AllEntries | QDir::System | QDir::Hidden); | 
| 1193 |  | 
| 1194 |     // Can't simply verify if the model returns a valid model index for a special file | 
| 1195 |     // as it will always return a valid index for existing files, | 
| 1196 |     // even if the file is not visible with the given filter. | 
| 1197 |  | 
| 1198 |     const QModelIndex rootIndex = model.setRootPath(QStringLiteral("/dev/" )); | 
| 1199 |     const QString testFileName = QStringLiteral("null" ); | 
| 1200 |  | 
| 1201 |     QTRY_VERIFY(fileListUnderIndex(&model, rootIndex).contains(testFileName)); | 
| 1202 |  | 
| 1203 |     model.setFilter(QDir::AllEntries | QDir::Hidden); | 
| 1204 |  | 
| 1205 |     QTRY_VERIFY(!fileListUnderIndex(&model, rootIndex).contains(testFileName)); | 
| 1206 | } | 
| 1207 |  | 
| 1208 | void tst_QFileSystemModel::fileInfo() | 
| 1209 | { | 
| 1210 |     QFileSystemModel model; | 
| 1211 |     QModelIndex idx; | 
| 1212 |  | 
| 1213 |     QVERIFY(model.fileInfo(idx).filePath().isEmpty()); | 
| 1214 |  | 
| 1215 |     const QString dirPath = flatDirTestPath; | 
| 1216 |     QDir dir(dirPath); | 
| 1217 |     const QString subdir = QStringLiteral("subdir" ); | 
| 1218 |     QVERIFY(dir.mkdir(subdir)); | 
| 1219 |     const QString subdirPath = dir.absoluteFilePath(fileName: subdir); | 
| 1220 |  | 
| 1221 |     idx = model.setRootPath(subdirPath); | 
| 1222 |     QCOMPARE(model.fileInfo(idx), QFileInfo(subdirPath)); | 
| 1223 |     idx = model.setRootPath(dirPath); | 
| 1224 |     QCOMPARE(model.fileInfo(idx), QFileInfo(dirPath)); | 
| 1225 | } | 
| 1226 |  | 
| 1227 | QTEST_MAIN(tst_QFileSystemModel) | 
| 1228 | #include "tst_qfilesystemmodel.moc" | 
| 1229 |  | 
| 1230 |  |