| 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 | #include <QtTest/QtTest> | 
| 30 |  | 
| 31 | #include <qfile.h> | 
| 32 | #include <qdir.h> | 
| 33 | #include <qcoreapplication.h> | 
| 34 | #include <qtemporaryfile.h> | 
| 35 | #include <qtemporarydir.h> | 
| 36 | #include <qdir.h> | 
| 37 | #include <qfileinfo.h> | 
| 38 | #include <qstorageinfo.h> | 
| 39 | #ifdef Q_OS_UNIX | 
| 40 | #include <errno.h> | 
| 41 | #include <fcntl.h> | 
| 42 | #include <unistd.h> | 
| 43 | #include <sys/stat.h> | 
| 44 | #include <sys/types.h> | 
| 45 | #ifndef Q_OS_VXWORKS | 
| 46 | #include <pwd.h> | 
| 47 | #endif | 
| 48 | #endif | 
| 49 | #ifdef Q_OS_WIN | 
| 50 | #include <qt_windows.h> | 
| 51 | #if !defined(Q_OS_WINRT) | 
| 52 | #include <private/qwinregistry_p.h> | 
| 53 | #include <lm.h> | 
| 54 | #endif | 
| 55 | #endif | 
| 56 | #include <qplatformdefs.h> | 
| 57 | #include <qdebug.h> | 
| 58 | #if defined(Q_OS_WIN) | 
| 59 | #include "../../../network-settings.h" | 
| 60 | #endif | 
| 61 | #include <private/qfileinfo_p.h> | 
| 62 | #include "../../../../shared/filesystem.h" | 
| 63 |  | 
| 64 | #if defined(Q_OS_VXWORKS) || defined(Q_OS_WINRT) | 
| 65 | #define Q_NO_SYMLINKS | 
| 66 | #endif | 
| 67 |  | 
| 68 | #if defined(Q_OS_WIN) | 
| 69 | QT_BEGIN_NAMESPACE | 
| 70 | extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; | 
| 71 | QT_END_NAMESPACE | 
| 72 | #  ifndef Q_OS_WINRT | 
| 73 | bool IsUserAdmin(); | 
| 74 | #  endif | 
| 75 | #endif | 
| 76 |  | 
| 77 | inline bool qIsLikelyToBeFat(const QString &path) | 
| 78 | { | 
| 79 |     QByteArray name = QStorageInfo(path).fileSystemType().toLower(); | 
| 80 |     return name.contains(c: "fat" ) || name.contains(c: "msdos" ); | 
| 81 | } | 
| 82 |  | 
| 83 | inline bool qIsLikelyToBeNfs(const QString &path) | 
| 84 | { | 
| 85 | #ifdef Q_OS_WIN | 
| 86 |     Q_UNUSED(path); | 
| 87 |     return false; | 
| 88 | #else | 
| 89 |     QByteArray type = QStorageInfo(path).fileSystemType(); | 
| 90 |     const char *name = type.constData(); | 
| 91 |  | 
| 92 |     return (qstrncmp(str1: name, str2: "nfs" , len: 3) == 0 | 
| 93 |             || qstrncmp(str1: name, str2: "autofs" , len: 6) == 0 | 
| 94 |             || qstrncmp(str1: name, str2: "autofsng" , len: 8) == 0 | 
| 95 |             || qstrncmp(str1: name, str2: "cachefs" , len: 7) == 0); | 
| 96 | #endif | 
| 97 | } | 
| 98 |  | 
| 99 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 100 | #  ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE // MinGW | 
| 101 | #    define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2) | 
| 102 | #  endif | 
| 103 |  | 
| 104 | static DWORD createSymbolicLink(const QString &symLinkName, const QString &target, | 
| 105 |                                 QString *errorMessage) | 
| 106 | { | 
| 107 |     DWORD result = ERROR_SUCCESS; | 
| 108 |     const QString nativeSymLinkName = QDir::toNativeSeparators(symLinkName); | 
| 109 |     const QString nativeTarget = QDir::toNativeSeparators(target); | 
| 110 |     DWORD flags = 0; | 
| 111 |     if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14972)) | 
| 112 |         flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; | 
| 113 |     if (QFileInfo(target).isDir()) | 
| 114 |         flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; | 
| 115 |     if (CreateSymbolicLink(reinterpret_cast<const wchar_t*>(nativeSymLinkName.utf16()), | 
| 116 |                            reinterpret_cast<const wchar_t*>(nativeTarget.utf16()), flags) == FALSE) { | 
| 117 |         result = GetLastError(); | 
| 118 |         QTextStream(errorMessage) << "CreateSymbolicLink("  <<  nativeSymLinkName << ", "  | 
| 119 |             << nativeTarget << ", 0x"  << hex << flags << dec << ") failed with error "  << result | 
| 120 |             << ": "  << qt_error_string(int(result)); | 
| 121 |     } | 
| 122 |     return result; | 
| 123 | } | 
| 124 |  | 
| 125 | static QByteArray msgInsufficientPrivileges(const QString &errorMessage) | 
| 126 | { | 
| 127 |     return "Insufficient privileges ("  + errorMessage.toLocal8Bit() + ')'; | 
| 128 | } | 
| 129 | #endif  // Q_OS_WIN && !Q_OS_WINRT | 
| 130 |  | 
| 131 | static QString seedAndTemplate() | 
| 132 | { | 
| 133 |     QString base; | 
| 134 | #if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID) | 
| 135 |     // use XDG_RUNTIME_DIR as it's a fully-capable FS | 
| 136 |     base = QStandardPaths::writableLocation(type: QStandardPaths::RuntimeLocation); | 
| 137 | #endif | 
| 138 |     if (base.isEmpty()) | 
| 139 |         base = QDir::tempPath(); | 
| 140 |     return base + "/tst_qfileinfo-XXXXXX" ; | 
| 141 | } | 
| 142 |  | 
| 143 | static QByteArray msgDoesNotExist(const QString &name) | 
| 144 | { | 
| 145 |     return (QLatin1Char('"') + QDir::toNativeSeparators(pathName: name) | 
| 146 |         + QLatin1String("\" does not exist." )).toLocal8Bit(); | 
| 147 | } | 
| 148 |  | 
| 149 | static QByteArray msgIsNoDirectory(const QString &name) | 
| 150 | { | 
| 151 |     return (QLatin1Char('"') + QDir::toNativeSeparators(pathName: name) | 
| 152 |         + QLatin1String("\" is not a directory." )).toLocal8Bit(); | 
| 153 | } | 
| 154 |  | 
| 155 | static QByteArray msgIsNotRoot(const QString &name) | 
| 156 | { | 
| 157 |     return (QLatin1Char('"') + QDir::toNativeSeparators(pathName: name) | 
| 158 |         + QLatin1String("\" is no root directory." )).toLocal8Bit(); | 
| 159 | } | 
| 160 |  | 
| 161 | class tst_QFileInfo : public QObject | 
| 162 | { | 
| 163 | Q_OBJECT | 
| 164 |  | 
| 165 | public: | 
| 166 |     tst_QFileInfo() : m_currentDir(QDir::currentPath()), m_dir(seedAndTemplate()) | 
| 167 |  {} | 
| 168 |  | 
| 169 | private slots: | 
| 170 |     void initTestCase(); | 
| 171 |     void cleanupTestCase(); | 
| 172 |  | 
| 173 |     void getSetCheck(); | 
| 174 |  | 
| 175 |     void copy(); | 
| 176 |  | 
| 177 |     void isFile_data(); | 
| 178 |     void isFile(); | 
| 179 |  | 
| 180 |     void isDir_data(); | 
| 181 |     void isDir(); | 
| 182 |  | 
| 183 |     void isRoot_data(); | 
| 184 |     void isRoot(); | 
| 185 |  | 
| 186 |     void exists_data(); | 
| 187 |     void exists(); | 
| 188 |  | 
| 189 |     void absolutePath_data(); | 
| 190 |     void absolutePath(); | 
| 191 |  | 
| 192 |     void absFilePath_data(); | 
| 193 |     void absFilePath(); | 
| 194 |  | 
| 195 |     void canonicalPath(); | 
| 196 |     void canonicalFilePath(); | 
| 197 |  | 
| 198 |     void fileName_data(); | 
| 199 |     void fileName(); | 
| 200 |  | 
| 201 |     void bundleName_data(); | 
| 202 |     void bundleName(); | 
| 203 |  | 
| 204 |     void dir_data(); | 
| 205 |     void dir(); | 
| 206 |  | 
| 207 |     void suffix_data(); | 
| 208 |     void suffix(); | 
| 209 |  | 
| 210 |     void completeSuffix_data(); | 
| 211 |     void completeSuffix(); | 
| 212 |  | 
| 213 |     void baseName_data(); | 
| 214 |     void baseName(); | 
| 215 |  | 
| 216 |     void completeBaseName_data(); | 
| 217 |     void completeBaseName(); | 
| 218 |  | 
| 219 |     void permission_data(); | 
| 220 |     void permission(); | 
| 221 |  | 
| 222 |     void size_data(); | 
| 223 |     void size(); | 
| 224 |  | 
| 225 |     void systemFiles(); | 
| 226 |  | 
| 227 |     void compare_data(); | 
| 228 |     void compare(); | 
| 229 |  | 
| 230 |     void consistent_data(); | 
| 231 |     void consistent(); | 
| 232 |  | 
| 233 |     void fileTimes_data(); | 
| 234 |     void fileTimes(); | 
| 235 |     void fakeFileTimes_data(); | 
| 236 |     void fakeFileTimes(); | 
| 237 |  | 
| 238 |     void isSymLink_data(); | 
| 239 |     void isSymLink(); | 
| 240 |  | 
| 241 |     void isSymbolicLink_data(); | 
| 242 |     void isSymbolicLink(); | 
| 243 |  | 
| 244 |     void isShortcut_data(); | 
| 245 |     void isShortcut(); | 
| 246 |  | 
| 247 |     void link_data(); | 
| 248 |     void link(); | 
| 249 |  | 
| 250 |     void isHidden_data(); | 
| 251 |     void isHidden(); | 
| 252 | #if defined(Q_OS_MAC) | 
| 253 |     void isHiddenFromFinder(); | 
| 254 | #endif | 
| 255 |  | 
| 256 |     void isBundle_data(); | 
| 257 |     void isBundle(); | 
| 258 |  | 
| 259 |     void isNativePath_data(); | 
| 260 |     void isNativePath(); | 
| 261 |  | 
| 262 |     void refresh(); | 
| 263 |  | 
| 264 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 265 |     void ntfsJunctionPointsAndSymlinks_data(); | 
| 266 |     void ntfsJunctionPointsAndSymlinks(); | 
| 267 |     void brokenShortcut(); | 
| 268 | #endif | 
| 269 |  | 
| 270 |     void isWritable(); | 
| 271 |     void isExecutable(); | 
| 272 |     void testDecomposedUnicodeNames_data(); | 
| 273 |     void testDecomposedUnicodeNames(); | 
| 274 |  | 
| 275 |     void equalOperator() const; | 
| 276 |     void equalOperatorWithDifferentSlashes() const; | 
| 277 |     void notEqualOperator() const; | 
| 278 |  | 
| 279 |     void detachingOperations(); | 
| 280 |  | 
| 281 | #if !defined(Q_OS_WINRT) | 
| 282 |     void owner(); | 
| 283 | #endif | 
| 284 |     void group(); | 
| 285 |  | 
| 286 |     void invalidState_data(); | 
| 287 |     void invalidState(); | 
| 288 |     void nonExistingFile(); | 
| 289 |  | 
| 290 | private: | 
| 291 |     const QString m_currentDir; | 
| 292 |     QString m_sourceFile; | 
| 293 |     QString m_proFile; | 
| 294 |     QString m_resourcesDir; | 
| 295 |     QTemporaryDir m_dir; | 
| 296 |     QSharedPointer<QTemporaryDir> m_dataDir; | 
| 297 | }; | 
| 298 |  | 
| 299 | void tst_QFileInfo::initTestCase() | 
| 300 | { | 
| 301 |     m_dataDir = QEXTRACTTESTDATA("/testdata" ); | 
| 302 |     QVERIFY(m_dataDir); | 
| 303 |     const QString dataPath = m_dataDir->path(); | 
| 304 |     QVERIFY(!dataPath.isEmpty()); | 
| 305 |  | 
| 306 |     m_sourceFile = dataPath + QLatin1String("/tst_qfileinfo.cpp" ); | 
| 307 |     m_resourcesDir = dataPath + QLatin1String("/resources" ); | 
| 308 |     m_proFile = dataPath + QLatin1String("/tst_qfileinfo.pro" ); | 
| 309 |  | 
| 310 |     QVERIFY2(m_dir.isValid(), | 
| 311 |              ("Failed to create temporary dir: "  + m_dir.errorString()).toUtf8()); | 
| 312 |     QVERIFY(QDir::setCurrent(m_dir.path())); | 
| 313 | } | 
| 314 |  | 
| 315 | void tst_QFileInfo::cleanupTestCase() | 
| 316 | { | 
| 317 |     QDir::setCurrent(m_currentDir); // Release temporary directory so that it can be deleted on Windows | 
| 318 | } | 
| 319 |  | 
| 320 | // Testing get/set functions | 
| 321 | void tst_QFileInfo::getSetCheck() | 
| 322 | { | 
| 323 |     QFileInfo obj1; | 
| 324 |     // bool QFileInfo::caching() | 
| 325 |     // void QFileInfo::setCaching(bool) | 
| 326 |     obj1.setCaching(false); | 
| 327 |     QCOMPARE(false, obj1.caching()); | 
| 328 |     obj1.setCaching(true); | 
| 329 |     QCOMPARE(true, obj1.caching()); | 
| 330 | } | 
| 331 |  | 
| 332 | static QFileInfoPrivate* getPrivate(QFileInfo &info) | 
| 333 | { | 
| 334 |     return (*reinterpret_cast<QFileInfoPrivate**>(&info)); | 
| 335 | } | 
| 336 |  | 
| 337 | void tst_QFileInfo::copy() | 
| 338 | { | 
| 339 |     QTemporaryFile t; | 
| 340 |     QVERIFY2(t.open(), qPrintable(t.errorString())); | 
| 341 |     QFileInfo info(t.fileName()); | 
| 342 |     QVERIFY(info.exists()); | 
| 343 |  | 
| 344 |     //copy constructor | 
| 345 |     QFileInfo info2(info); | 
| 346 |     QFileInfoPrivate *privateInfo = getPrivate(info); | 
| 347 |     QFileInfoPrivate *privateInfo2 = getPrivate(info&: info2); | 
| 348 |     QCOMPARE(privateInfo, privateInfo2); | 
| 349 |  | 
| 350 |     //operator = | 
| 351 |     QFileInfo info3 = info; | 
| 352 |     QFileInfoPrivate *privateInfo3 = getPrivate(info&: info3); | 
| 353 |     QCOMPARE(privateInfo, privateInfo3); | 
| 354 |     QCOMPARE(privateInfo2, privateInfo3); | 
| 355 |  | 
| 356 |     //refreshing info3 will detach it | 
| 357 |     QFile file(info.absoluteFilePath()); | 
| 358 |     QVERIFY(file.open(QFile::WriteOnly)); | 
| 359 |     QCOMPARE(file.write("JAJAJAA" ), qint64(7)); | 
| 360 |     file.flush(); | 
| 361 |  | 
| 362 |     QTest::qWait(ms: 250); | 
| 363 | #if defined(Q_OS_WIN) | 
| 364 |     file.close(); | 
| 365 | #endif | 
| 366 |     info3.refresh(); | 
| 367 |     privateInfo3 = getPrivate(info&: info3); | 
| 368 |     QVERIFY(privateInfo != privateInfo3); | 
| 369 |     QVERIFY(privateInfo2 != privateInfo3); | 
| 370 |     QCOMPARE(privateInfo, privateInfo2); | 
| 371 | } | 
| 372 |  | 
| 373 | void tst_QFileInfo::isFile_data() | 
| 374 | { | 
| 375 |     QTest::addColumn<QString>(name: "path" ); | 
| 376 |     QTest::addColumn<bool>(name: "expected" ); | 
| 377 |  | 
| 378 |     QTest::newRow(dataTag: "data0" ) << QDir::currentPath() << false; | 
| 379 |     QTest::newRow(dataTag: "data1" ) << m_sourceFile << true; | 
| 380 |     QTest::newRow(dataTag: "data2" ) << ":/tst_qfileinfo/resources/"  << false; | 
| 381 |     QTest::newRow(dataTag: "data3" ) << ":/tst_qfileinfo/resources/file1"  << true; | 
| 382 |     QTest::newRow(dataTag: "data4" ) << ":/tst_qfileinfo/resources/afilethatshouldnotexist"  << false; | 
| 383 | } | 
| 384 |  | 
| 385 | void tst_QFileInfo::isFile() | 
| 386 | { | 
| 387 |     QFETCH(QString, path); | 
| 388 |     QFETCH(bool, expected); | 
| 389 |  | 
| 390 |     QFileInfo fi(path); | 
| 391 |     QCOMPARE(fi.isFile(), expected); | 
| 392 | } | 
| 393 |  | 
| 394 |  | 
| 395 | void tst_QFileInfo::isDir_data() | 
| 396 | { | 
| 397 |     // create a broken symlink | 
| 398 |     QFile::remove(fileName: "brokenlink.lnk" ); | 
| 399 |     QFile::remove(fileName: "dummyfile" ); | 
| 400 |     QFile file3("dummyfile" ); | 
| 401 |     file3.open(flags: QIODevice::WriteOnly); | 
| 402 |     if (file3.link(newName: "brokenlink.lnk" )) { | 
| 403 |         file3.remove(); | 
| 404 |         QFileInfo info3("brokenlink.lnk" ); | 
| 405 |         QVERIFY( info3.isSymLink() ); | 
| 406 |     } | 
| 407 |  | 
| 408 |     QTest::addColumn<QString>(name: "path" ); | 
| 409 |     QTest::addColumn<bool>(name: "expected" ); | 
| 410 |  | 
| 411 |     QTest::newRow(dataTag: "data0" ) << QDir::currentPath() << true; | 
| 412 |     QTest::newRow(dataTag: "data1" ) << m_sourceFile << false; | 
| 413 |     QTest::newRow(dataTag: "data2" ) << ":/tst_qfileinfo/resources/"  << true; | 
| 414 |     QTest::newRow(dataTag: "data3" ) << ":/tst_qfileinfo/resources/file1"  << false; | 
| 415 |     QTest::newRow(dataTag: "data4" ) << ":/tst_qfileinfo/resources/afilethatshouldnotexist"  << false; | 
| 416 |  | 
| 417 |     QTest::newRow(dataTag: "simple dir" ) << m_resourcesDir << true; | 
| 418 |     QTest::newRow(dataTag: "simple dir with slash" ) << (m_resourcesDir + QLatin1Char('/')) << true; | 
| 419 |  | 
| 420 |     QTest::newRow(dataTag: "broken link" ) << "brokenlink.lnk"  << false; | 
| 421 |  | 
| 422 | #if (defined(Q_OS_WIN) && !defined(Q_OS_WINRT)) | 
| 423 |     QTest::newRow("drive 1" ) << "c:"  << true; | 
| 424 |     QTest::newRow("drive 2" ) << "c:/"  << true; | 
| 425 |     //QTest::newRow("drive 2") << "t:s" << false; | 
| 426 | #endif | 
| 427 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 428 |     const QString uncRoot = QStringLiteral("//" ) + QtNetworkSettings::winServerName(); | 
| 429 |     QTest::newRow("unc 1" ) << uncRoot << true; | 
| 430 |     QTest::newRow("unc 2" ) << uncRoot + QLatin1Char('/') << true; | 
| 431 |     QTest::newRow("unc 3" ) << uncRoot + "/testshare"  << true; | 
| 432 |     QTest::newRow("unc 4" ) << uncRoot + "/testshare/"  << true; | 
| 433 |     QTest::newRow("unc 5" ) << uncRoot + "/testshare/tmp"  << true; | 
| 434 |     QTest::newRow("unc 6" ) << uncRoot + "/testshare/tmp/"  << true; | 
| 435 |     QTest::newRow("unc 7" ) << uncRoot + "/testshare/adirthatshouldnotexist"  << false; | 
| 436 | #endif | 
| 437 | } | 
| 438 |  | 
| 439 | void tst_QFileInfo::isDir() | 
| 440 | { | 
| 441 |     QFETCH(QString, path); | 
| 442 |     QFETCH(bool, expected); | 
| 443 |  | 
| 444 |     const bool isDir = QFileInfo(path).isDir(); | 
| 445 |     if (expected) | 
| 446 |         QVERIFY2(isDir, msgIsNoDirectory(path).constData()); | 
| 447 |     else | 
| 448 |         QVERIFY(!isDir); | 
| 449 | } | 
| 450 |  | 
| 451 | void tst_QFileInfo::isRoot_data() | 
| 452 | { | 
| 453 |     QTest::addColumn<QString>(name: "path" ); | 
| 454 |     QTest::addColumn<bool>(name: "expected" ); | 
| 455 |     QTest::newRow(dataTag: "data0" ) << QDir::currentPath() << false; | 
| 456 |     QTest::newRow(dataTag: "data1" ) << "/"  << true; | 
| 457 |     QTest::newRow(dataTag: "data2" ) << "*"  << false; | 
| 458 |     QTest::newRow(dataTag: "data3" ) << "/*"  << false; | 
| 459 |     QTest::newRow(dataTag: "data4" ) << ":/tst_qfileinfo/resources/"  << false; | 
| 460 |     QTest::newRow(dataTag: "data5" ) << ":/"  << true; | 
| 461 |  | 
| 462 |     QTest::newRow(dataTag: "simple dir" ) << m_resourcesDir << false; | 
| 463 |     QTest::newRow(dataTag: "simple dir with slash" ) << (m_resourcesDir + QLatin1Char('/')) << false; | 
| 464 | #if (defined(Q_OS_WIN) && !defined(Q_OS_WINRT)) | 
| 465 |     QTest::newRow("drive 1" ) << "c:"  << false; | 
| 466 |     QTest::newRow("drive 2" ) << "c:/"  << true; | 
| 467 |     QTest::newRow("drive 3" ) << "p:/"  << false; | 
| 468 | #endif | 
| 469 |  | 
| 470 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 471 |     const QString uncRoot = QStringLiteral("//" ) + QtNetworkSettings::winServerName(); | 
| 472 |     QTest::newRow("unc 1" ) << uncRoot << true; | 
| 473 |     QTest::newRow("unc 2" ) << uncRoot + QLatin1Char('/') << true; | 
| 474 |     QTest::newRow("unc 3" ) << uncRoot + "/testshare"  << false; | 
| 475 |     QTest::newRow("unc 4" ) << uncRoot + "/testshare/"  << false; | 
| 476 |     QTest::newRow("unc 7" ) << "//ahostthatshouldnotexist"  << false; | 
| 477 | #endif | 
| 478 | } | 
| 479 |  | 
| 480 | void tst_QFileInfo::isRoot() | 
| 481 | { | 
| 482 |     QFETCH(QString, path); | 
| 483 |     QFETCH(bool, expected); | 
| 484 |  | 
| 485 |     const bool isRoot = QFileInfo(path).isRoot(); | 
| 486 |     if (expected) | 
| 487 |         QVERIFY2(isRoot, msgIsNotRoot(path).constData()); | 
| 488 |     else | 
| 489 |         QVERIFY(!isRoot); | 
| 490 | } | 
| 491 |  | 
| 492 | void tst_QFileInfo::exists_data() | 
| 493 | { | 
| 494 |     QTest::addColumn<QString>(name: "path" ); | 
| 495 |     QTest::addColumn<bool>(name: "expected" ); | 
| 496 |  | 
| 497 |     QTest::newRow(dataTag: "data0" ) << QDir::currentPath() << true; | 
| 498 |     QTest::newRow(dataTag: "data1" ) << m_sourceFile << true; | 
| 499 |     QTest::newRow(dataTag: "data2" ) << "/I/do_not_expect_this_path_to_exist/"  << false; | 
| 500 |     QTest::newRow(dataTag: "data3" ) << ":/tst_qfileinfo/resources/"  << true; | 
| 501 |     QTest::newRow(dataTag: "data4" ) << ":/tst_qfileinfo/resources/file1"  << true; | 
| 502 |     QTest::newRow(dataTag: "data5" ) << ":/I/do_not_expect_this_path_to_exist/"  << false; | 
| 503 |     QTest::newRow(dataTag: "data6" ) << (m_resourcesDir + "/*" ) << false; | 
| 504 |     QTest::newRow(dataTag: "data7" ) << (m_resourcesDir + "/*.foo" ) << false; | 
| 505 |     QTest::newRow(dataTag: "data8" ) << (m_resourcesDir + "/*.ext1" ) << false; | 
| 506 |     QTest::newRow(dataTag: "data9" ) << (m_resourcesDir + "/file?.ext1" ) << false; | 
| 507 |     QTest::newRow(dataTag: "data10" ) << "."  << true; | 
| 508 |  | 
| 509 |     // Skip for the WinRT case, as GetFileAttributesEx removes _any_ | 
| 510 |     // trailing whitespace and "." is a valid entry as seen in data10 | 
| 511 | #ifndef Q_OS_WINRT | 
| 512 |     QTest::newRow(dataTag: "data11" ) << ". "  << false; | 
| 513 | #endif | 
| 514 |     QTest::newRow(dataTag: "empty" ) << ""  << false; | 
| 515 |  | 
| 516 |     QTest::newRow(dataTag: "simple dir" ) << m_resourcesDir << true; | 
| 517 |     QTest::newRow(dataTag: "simple dir with slash" ) << (m_resourcesDir + QLatin1Char('/')) << true; | 
| 518 |  | 
| 519 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 520 |     const QString uncRoot = QStringLiteral("//" ) + QtNetworkSettings::winServerName(); | 
| 521 |     QTest::newRow("unc 1" ) << uncRoot << true; | 
| 522 |     QTest::newRow("unc 2" ) << uncRoot + QLatin1Char('/') << true; | 
| 523 |     QTest::newRow("unc 3" ) << uncRoot + "/testshare"  << true; | 
| 524 |     QTest::newRow("unc 4" ) << uncRoot + "/testshare/"  << true; | 
| 525 |     QTest::newRow("unc 5" ) << uncRoot + "/testshare/tmp"  << true; | 
| 526 |     QTest::newRow("unc 6" ) << uncRoot + "/testshare/tmp/"  << true; | 
| 527 |     QTest::newRow("unc 7" ) << uncRoot + "/testshare/adirthatshouldnotexist"  << false; | 
| 528 |     QTest::newRow("unc 8" ) << uncRoot + "/asharethatshouldnotexist"  << false; | 
| 529 |     QTest::newRow("unc 9" ) << "//ahostthatshouldnotexist"  << false; | 
| 530 | #endif | 
| 531 | } | 
| 532 |  | 
| 533 | void tst_QFileInfo::exists() | 
| 534 | { | 
| 535 |     QFETCH(QString, path); | 
| 536 |     QFETCH(bool, expected); | 
| 537 |  | 
| 538 |     QFileInfo fi(path); | 
| 539 |     const bool exists = fi.exists(); | 
| 540 |     QCOMPARE(exists, QFileInfo::exists(path)); | 
| 541 |     if (expected) | 
| 542 |         QVERIFY2(exists, msgDoesNotExist(path).constData()); | 
| 543 |     else | 
| 544 |         QVERIFY(!exists); | 
| 545 | } | 
| 546 |  | 
| 547 | void tst_QFileInfo::absolutePath_data() | 
| 548 | { | 
| 549 |     QTest::addColumn<QString>(name: "file" ); | 
| 550 |     QTest::addColumn<QString>(name: "path" ); | 
| 551 |     QTest::addColumn<QString>(name: "filename" ); | 
| 552 |  | 
| 553 |     QString drivePrefix; | 
| 554 | #if (defined(Q_OS_WIN) && !defined(Q_OS_WINRT)) | 
| 555 |     drivePrefix = QDir::currentPath().left(2); | 
| 556 |     QString nonCurrentDrivePrefix = | 
| 557 |         drivePrefix.left(1).compare("X" , Qt::CaseInsensitive) == 0 ? QString("Y:" ) : QString("X:" ); | 
| 558 |  | 
| 559 |     // Make sure drive-relative paths return correct absolute paths. | 
| 560 |     QTest::newRow("<current drive>:my.dll" ) << drivePrefix + "my.dll"  << QDir::currentPath() << "my.dll" ; | 
| 561 |     QTest::newRow("<not current drive>:my.dll" ) << nonCurrentDrivePrefix + "my.dll"  | 
| 562 |                                                 << nonCurrentDrivePrefix + "/"  | 
| 563 |                                                 << "my.dll" ; | 
| 564 | #elif defined(Q_OS_WINRT) | 
| 565 |     drivePrefix = QDir::currentPath().left(2); | 
| 566 | #endif | 
| 567 |     QTest::newRow(dataTag: "0" ) << "/machine/share/dir1/"  << drivePrefix + "/machine/share/dir1"  << "" ; | 
| 568 |     QTest::newRow(dataTag: "1" ) << "/machine/share/dir1"  << drivePrefix + "/machine/share"  << "dir1" ; | 
| 569 |     QTest::newRow(dataTag: "2" ) << "/usr/local/bin"  << drivePrefix + "/usr/local"  << "bin" ; | 
| 570 |     QTest::newRow(dataTag: "3" ) << "/usr/local/bin/"  << drivePrefix + "/usr/local/bin"  << "" ; | 
| 571 |     QTest::newRow(dataTag: "/test" ) << "/test"  << drivePrefix + "/"  << "test" ; | 
| 572 |  | 
| 573 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 574 |     QTest::newRow("c:\\autoexec.bat" ) << "c:\\autoexec.bat"  << "C:/"  | 
| 575 |                                       << "autoexec.bat" ; | 
| 576 |     QTest::newRow("c:autoexec.bat" ) << QDir::currentPath().left(2) + "autoexec.bat"  << QDir::currentPath() | 
| 577 |                                     << "autoexec.bat" ; | 
| 578 | #endif | 
| 579 |     QTest::newRow(dataTag: "QTBUG-19995.1" ) << drivePrefix + "/System/Library/StartupItems/../Frameworks"  | 
| 580 |                                    << drivePrefix + "/System/Library"  | 
| 581 |                                    << "Frameworks" ; | 
| 582 |     QTest::newRow(dataTag: "QTBUG-19995.2" ) << drivePrefix + "/System/Library/StartupItems/../Frameworks/"  | 
| 583 |                                    << drivePrefix + "/System/Library/Frameworks"  << "" ; | 
| 584 | } | 
| 585 |  | 
| 586 | void tst_QFileInfo::absolutePath() | 
| 587 | { | 
| 588 |     QFETCH(QString, file); | 
| 589 |     QFETCH(QString, path); | 
| 590 |     QFETCH(QString, filename); | 
| 591 |  | 
| 592 |     QFileInfo fi(file); | 
| 593 |  | 
| 594 |     QCOMPARE(fi.absolutePath(), path); | 
| 595 |     QCOMPARE(fi.fileName(), filename); | 
| 596 | } | 
| 597 |  | 
| 598 | void tst_QFileInfo::absFilePath_data() | 
| 599 | { | 
| 600 |     QTest::addColumn<QString>(name: "file" ); | 
| 601 |     QTest::addColumn<QString>(name: "expected" ); | 
| 602 |  | 
| 603 |     QTest::newRow(dataTag: "relativeFile" ) << "tmp.txt"  << QDir::currentPath() + "/tmp.txt" ; | 
| 604 |     QTest::newRow(dataTag: "relativeFileInSubDir" ) << "temp/tmp.txt"  << QDir::currentPath() + "/"  + "temp/tmp.txt" ; | 
| 605 |     QString drivePrefix; | 
| 606 | #if defined(Q_OS_WIN) | 
| 607 |     QString curr = QDir::currentPath(); | 
| 608 |  | 
| 609 |     curr.remove(0, 2);   // Make it a absolute path with no drive specifier: \depot\qt-4.2\tests\auto\qfileinfo | 
| 610 |     QTest::newRow("." )            << curr << QDir::currentPath(); | 
| 611 |     QTest::newRow("absFilePath" ) << "c:\\home\\andy\\tmp.txt"  << "C:/home/andy/tmp.txt" ; | 
| 612 |  | 
| 613 |     // Make sure drive-relative paths return correct absolute paths. | 
| 614 |     drivePrefix = QDir::currentPath().left(2); | 
| 615 |     QString nonCurrentDrivePrefix = | 
| 616 |         drivePrefix.left(1).compare("X" , Qt::CaseInsensitive) == 0 ? QString("Y:" ) : QString("X:" ); | 
| 617 |  | 
| 618 |     QTest::newRow("absFilePathWithoutSlash" ) << drivePrefix + "tmp.txt"  << QDir::currentPath() + "/tmp.txt" ; | 
| 619 |     QTest::newRow("<current drive>:my.dll" ) << drivePrefix + "temp/my.dll"  << QDir::currentPath() + "/temp/my.dll" ; | 
| 620 |     QTest::newRow("<not current drive>:my.dll" ) << nonCurrentDrivePrefix + "temp/my.dll"  | 
| 621 |                                                 << nonCurrentDrivePrefix + "/temp/my.dll" ; | 
| 622 | #else | 
| 623 |     QTest::newRow(dataTag: "absFilePath" ) << "/home/andy/tmp.txt"  << "/home/andy/tmp.txt" ; | 
| 624 | #endif | 
| 625 |     QTest::newRow(dataTag: "QTBUG-19995" ) << drivePrefix + "/System/Library/StartupItems/../Frameworks"  | 
| 626 |                                  << drivePrefix + "/System/Library/Frameworks" ; | 
| 627 | } | 
| 628 |  | 
| 629 | void tst_QFileInfo::absFilePath() | 
| 630 | { | 
| 631 |     QFETCH(QString, file); | 
| 632 |     QFETCH(QString, expected); | 
| 633 |  | 
| 634 |     QFileInfo fi(file); | 
| 635 | #if defined(Q_OS_WIN) | 
| 636 |     QVERIFY(QString::compare(fi.absoluteFilePath(), expected, Qt::CaseInsensitive) == 0); | 
| 637 | #else | 
| 638 |     QCOMPARE(fi.absoluteFilePath(), expected); | 
| 639 | #endif | 
| 640 | } | 
| 641 |  | 
| 642 | void tst_QFileInfo::canonicalPath() | 
| 643 | { | 
| 644 |     QTemporaryFile tempFile; | 
| 645 |     tempFile.setAutoRemove(true); | 
| 646 |     QVERIFY2(tempFile.open(), qPrintable(tempFile.errorString())); | 
| 647 |     QFileInfo fi(tempFile.fileName()); | 
| 648 |     QCOMPARE(fi.canonicalPath(), QFileInfo(QDir::tempPath()).canonicalFilePath()); | 
| 649 | } | 
| 650 |  | 
| 651 | class FileDeleter { | 
| 652 |     Q_DISABLE_COPY(FileDeleter) | 
| 653 | public: | 
| 654 |     explicit FileDeleter(const QString fileName) : m_fileName(fileName) {} | 
| 655 |     ~FileDeleter() { QFile::remove(fileName: m_fileName); } | 
| 656 |  | 
| 657 | private: | 
| 658 |     const QString m_fileName; | 
| 659 | }; | 
| 660 |  | 
| 661 | void tst_QFileInfo::canonicalFilePath() | 
| 662 | { | 
| 663 |     const QString fileName("tmp.canon" ); | 
| 664 |     QFile tempFile(fileName); | 
| 665 |     QVERIFY(tempFile.open(QFile::WriteOnly)); | 
| 666 |     QFileInfo fi(tempFile.fileName()); | 
| 667 |     QCOMPARE(fi.canonicalFilePath(), QDir::currentPath() + "/"  + fileName); | 
| 668 |     fi = QFileInfo(tempFile.fileName() + QString::fromLatin1(str: "/" )); | 
| 669 |     QCOMPARE(fi.canonicalFilePath(), QString::fromLatin1("" )); | 
| 670 |     tempFile.remove(); | 
| 671 |  | 
| 672 |     // This used to crash on Mac, verify that it doesn't anymore. | 
| 673 |     QFileInfo info("/tmp/../../../../../../../../../../../../../../../../../" ); | 
| 674 |     info.canonicalFilePath(); | 
| 675 |  | 
| 676 | #if defined(Q_OS_UNIX) | 
| 677 |     // If this file exists, you can't log in to run this test ... | 
| 678 |     const QString notExtantPath(QStringLiteral("/etc/nologin" )); | 
| 679 |     QFileInfo notExtant(notExtantPath); | 
| 680 |     QCOMPARE(notExtant.canonicalFilePath(), QString()); | 
| 681 |  | 
| 682 |     // A path with a non-directory as a directory component also doesn't exist: | 
| 683 |     const QString badDirPath(QStringLiteral("/dev/null/sub/dir/n'existe.pas" )); | 
| 684 |     QFileInfo badDir(badDirPath); | 
| 685 |     QCOMPARE(badDir.canonicalFilePath(), QString()); | 
| 686 |  | 
| 687 |     // This used to crash on Mac | 
| 688 |     QFileInfo dontCrash(QLatin1String("/" )); | 
| 689 |     QCOMPARE(dontCrash.canonicalFilePath(), QLatin1String("/" )); | 
| 690 | #endif | 
| 691 |  | 
| 692 | #ifndef Q_OS_WIN | 
| 693 |     // test symlinks | 
| 694 |     QFile::remove(fileName: "link.lnk" ); | 
| 695 |     { | 
| 696 |         QFile file(m_sourceFile); | 
| 697 |         if (file.link(newName: "link.lnk" )) { | 
| 698 |             QFileInfo info1(file); | 
| 699 |             QFileInfo info2("link.lnk" ); | 
| 700 |             QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath()); | 
| 701 |         } | 
| 702 |     } | 
| 703 |  | 
| 704 |     const QString dirSymLinkName = QLatin1String("tst_qfileinfo" ) | 
| 705 |         + QDateTime::currentDateTime().toString(format: QLatin1String("yyMMddhhmmss" )); | 
| 706 |     const QString link(QDir::tempPath() + QLatin1Char('/') + dirSymLinkName); | 
| 707 |     FileDeleter dirSymLinkDeleter(link); | 
| 708 |  | 
| 709 |     { | 
| 710 |         QFile file(QDir::currentPath()); | 
| 711 |         if (file.link(newName: link)) { | 
| 712 |             QFile tempfile("tempfile.txt" ); | 
| 713 |             tempfile.open(flags: QIODevice::ReadWrite); | 
| 714 |             tempfile.write(data: "This file is generated by the QFileInfo autotest." ); | 
| 715 |             QVERIFY(tempfile.flush()); | 
| 716 |             tempfile.close(); | 
| 717 |  | 
| 718 |             QFileInfo info1("tempfile.txt" ); | 
| 719 |             QFileInfo info2(link + QDir::separator() + "tempfile.txt" ); | 
| 720 |  | 
| 721 |             QVERIFY(info1.exists()); | 
| 722 |             QVERIFY(info2.exists()); | 
| 723 |             QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath()); | 
| 724 |  | 
| 725 |             QFileInfo info3(link + QDir::separator() + "link.lnk" ); | 
| 726 |             QFileInfo info4(m_sourceFile); | 
| 727 |             QVERIFY(!info3.canonicalFilePath().isEmpty()); | 
| 728 |             QCOMPARE(info4.canonicalFilePath(), info3.canonicalFilePath()); | 
| 729 |  | 
| 730 |             tempfile.remove(); | 
| 731 |         } | 
| 732 |     } | 
| 733 |     { | 
| 734 |         QString link(QDir::tempPath() + QLatin1Char('/') + dirSymLinkName | 
| 735 |                      + "/link_to_tst_qfileinfo" ); | 
| 736 |         QFile::remove(fileName: link); | 
| 737 |  | 
| 738 |         QFile file(QDir::tempPath() + QLatin1Char('/') +  dirSymLinkName | 
| 739 |                    + "tst_qfileinfo.cpp" ); | 
| 740 |         if (file.link(newName: link)) | 
| 741 |         { | 
| 742 |             QFileInfo info1("tst_qfileinfo.cpp" ); | 
| 743 |             QFileInfo info2(link); | 
| 744 |             QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath()); | 
| 745 |         } | 
| 746 |     } | 
| 747 | #endif | 
| 748 |  | 
| 749 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 750 |     { | 
| 751 |         QString errorMessage; | 
| 752 |         const QString linkTarget = QStringLiteral("res" ); | 
| 753 |         const DWORD dwErr = createSymbolicLink(linkTarget, m_resourcesDir, &errorMessage); | 
| 754 |         if (dwErr == ERROR_PRIVILEGE_NOT_HELD) | 
| 755 |             QSKIP(msgInsufficientPrivileges(errorMessage)); | 
| 756 |         QVERIFY2(dwErr == ERROR_SUCCESS, qPrintable(errorMessage)); | 
| 757 |         QString currentPath = QDir::currentPath(); | 
| 758 |         QVERIFY(QDir::setCurrent(linkTarget)); | 
| 759 |         const QString actualCanonicalPath = QFileInfo("file1" ).canonicalFilePath(); | 
| 760 |         QVERIFY(QDir::setCurrent(currentPath)); | 
| 761 |         QCOMPARE(actualCanonicalPath, m_resourcesDir + QStringLiteral("/file1" )); | 
| 762 |  | 
| 763 |         QDir::current().rmdir(linkTarget); | 
| 764 |     } | 
| 765 | #endif | 
| 766 |  | 
| 767 | #ifdef Q_OS_DARWIN | 
| 768 |     { | 
| 769 |         // Check if canonicalFilePath's result is in Composed normalization form. | 
| 770 |         QString path = QString::fromLatin1("caf\xe9" ); | 
| 771 |         QDir dir(QDir::tempPath()); | 
| 772 |         dir.mkdir(path); | 
| 773 |         QString canonical = QFileInfo(dir.filePath(path)).canonicalFilePath(); | 
| 774 |         QString roundtrip = QFile::decodeName(QFile::encodeName(canonical)); | 
| 775 |         QCOMPARE(canonical, roundtrip); | 
| 776 |         dir.rmdir(path); | 
| 777 |     } | 
| 778 | #endif | 
| 779 | } | 
| 780 |  | 
| 781 | void tst_QFileInfo::fileName_data() | 
| 782 | { | 
| 783 |     QTest::addColumn<QString>(name: "file" ); | 
| 784 |     QTest::addColumn<QString>(name: "expected" ); | 
| 785 |  | 
| 786 |     QTest::newRow(dataTag: "relativeFile" ) << "tmp.txt"  << "tmp.txt" ; | 
| 787 |     QTest::newRow(dataTag: "relativeFileInSubDir" ) << "temp/tmp.txt"  << "tmp.txt" ; | 
| 788 | #if defined(Q_OS_WIN) | 
| 789 |     QTest::newRow("absFilePath" ) << "c:\\home\\andy\\tmp.txt"  << "tmp.txt" ; | 
| 790 |     QTest::newRow("driveWithNoSlash" ) << "c:tmp.txt"  << "tmp.txt" ; | 
| 791 | #else | 
| 792 |     QTest::newRow(dataTag: "absFilePath" ) << "/home/andy/tmp.txt"  << "tmp.txt" ; | 
| 793 | #endif | 
| 794 |     QTest::newRow(dataTag: "resource1" ) << ":/tst_qfileinfo/resources/file1.ext1"  << "file1.ext1" ; | 
| 795 |     QTest::newRow(dataTag: "resource2" ) << ":/tst_qfileinfo/resources/file1.ext1.ext2"  << "file1.ext1.ext2" ; | 
| 796 |  | 
| 797 |     QTest::newRow(dataTag: "ending slash [small]" ) << QString::fromLatin1(str: "/a/" ) << QString::fromLatin1(str: "" ); | 
| 798 |     QTest::newRow(dataTag: "no ending slash [small]" ) << QString::fromLatin1(str: "/a" ) << QString::fromLatin1(str: "a" ); | 
| 799 |  | 
| 800 |     QTest::newRow(dataTag: "ending slash" ) << QString::fromLatin1(str: "/somedir/" ) << QString::fromLatin1(str: "" ); | 
| 801 |     QTest::newRow(dataTag: "no ending slash" ) << QString::fromLatin1(str: "/somedir" ) << QString::fromLatin1(str: "somedir" ); | 
| 802 | } | 
| 803 |  | 
| 804 | void tst_QFileInfo::fileName() | 
| 805 | { | 
| 806 |     QFETCH(QString, file); | 
| 807 |     QFETCH(QString, expected); | 
| 808 |  | 
| 809 |     QFileInfo fi(file); | 
| 810 |     QCOMPARE(fi.fileName(), expected); | 
| 811 | } | 
| 812 |  | 
| 813 | void tst_QFileInfo::bundleName_data() | 
| 814 | { | 
| 815 |     QTest::addColumn<QString>(name: "file" ); | 
| 816 |     QTest::addColumn<QString>(name: "expected" ); | 
| 817 |  | 
| 818 |     QTest::newRow(dataTag: "root" ) << "/"  << "" ; | 
| 819 |     QTest::newRow(dataTag: "etc" ) << "/etc"  << "" ; | 
| 820 | #ifdef Q_OS_MAC | 
| 821 |     QTest::newRow("safari" ) << "/Applications/Safari.app"  << "Safari" ; | 
| 822 | #endif | 
| 823 | } | 
| 824 |  | 
| 825 | void tst_QFileInfo::bundleName() | 
| 826 | { | 
| 827 |     QFETCH(QString, file); | 
| 828 |     QFETCH(QString, expected); | 
| 829 |  | 
| 830 |     QFileInfo fi(file); | 
| 831 |     QCOMPARE(fi.bundleName(), expected); | 
| 832 | } | 
| 833 |  | 
| 834 | void tst_QFileInfo::dir_data() | 
| 835 | { | 
| 836 |     QTest::addColumn<QString>(name: "file" ); | 
| 837 |     QTest::addColumn<bool>(name: "absPath" ); | 
| 838 |     QTest::addColumn<QString>(name: "expected" ); | 
| 839 |  | 
| 840 |     QTest::newRow(dataTag: "relativeFile" ) << "tmp.txt"  << false << "." ; | 
| 841 |     QTest::newRow(dataTag: "relativeFileAbsPath" ) << "tmp.txt"  << true << QDir::currentPath(); | 
| 842 |     QTest::newRow(dataTag: "relativeFileInSubDir" ) << "temp/tmp.txt"  << false << "temp" ; | 
| 843 |     QTest::newRow(dataTag: "relativeFileInSubDirAbsPath" ) << "temp/tmp.txt"  << true << QDir::currentPath() + "/temp" ; | 
| 844 |     QTest::newRow(dataTag: "absFilePath" ) << QDir::currentPath() + "/tmp.txt"  << false << QDir::currentPath(); | 
| 845 |     QTest::newRow(dataTag: "absFilePathAbsPath" ) << QDir::currentPath() + "/tmp.txt"  << true << QDir::currentPath(); | 
| 846 |     QTest::newRow(dataTag: "resource1" ) << ":/tst_qfileinfo/resources/file1.ext1"  << true << ":/tst_qfileinfo/resources" ; | 
| 847 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 848 |     QTest::newRow("driveWithSlash" ) << "C:/file1.ext1.ext2"  << true << "C:/" ; | 
| 849 |     QTest::newRow("driveWithoutSlash" ) << QDir::currentPath().left(2) + "file1.ext1.ext2"  << false << QDir::currentPath().left(2); | 
| 850 | #endif | 
| 851 | } | 
| 852 |  | 
| 853 | void tst_QFileInfo::dir() | 
| 854 | { | 
| 855 |     QFETCH(QString, file); | 
| 856 |     QFETCH(bool, absPath); | 
| 857 |     QFETCH(QString, expected); | 
| 858 |  | 
| 859 |     QFileInfo fi(file); | 
| 860 |     if (absPath) { | 
| 861 |         QCOMPARE(fi.absolutePath(), expected); | 
| 862 |         QCOMPARE(fi.absoluteDir().path(), expected); | 
| 863 |     } else { | 
| 864 |         QCOMPARE(fi.path(), expected); | 
| 865 |         QCOMPARE(fi.dir().path(), expected); | 
| 866 |     } | 
| 867 | } | 
| 868 |  | 
| 869 |  | 
| 870 | void tst_QFileInfo::suffix_data() | 
| 871 | { | 
| 872 |     QTest::addColumn<QString>(name: "file" ); | 
| 873 |     QTest::addColumn<QString>(name: "expected" ); | 
| 874 |  | 
| 875 |     QTest::newRow(dataTag: "noextension0" ) << "file"  << "" ; | 
| 876 |     QTest::newRow(dataTag: "noextension1" ) << "/path/to/file"  << "" ; | 
| 877 |     QTest::newRow(dataTag: "data0" ) << "file.tar"  << "tar" ; | 
| 878 |     QTest::newRow(dataTag: "data1" ) << "file.tar.gz"  << "gz" ; | 
| 879 |     QTest::newRow(dataTag: "data2" ) << "/path/file/file.tar.gz"  << "gz" ; | 
| 880 |     QTest::newRow(dataTag: "data3" ) << "/path/file.tar"  << "tar" ; | 
| 881 |     QTest::newRow(dataTag: "resource1" ) << ":/tst_qfileinfo/resources/file1.ext1"  << "ext1" ; | 
| 882 |     QTest::newRow(dataTag: "resource2" ) << ":/tst_qfileinfo/resources/file1.ext1.ext2"  << "ext2" ; | 
| 883 |     QTest::newRow(dataTag: "hidden1" ) << ".ext1"  << "ext1" ; | 
| 884 |     QTest::newRow(dataTag: "hidden1" ) << ".ext"  << "ext" ; | 
| 885 |     QTest::newRow(dataTag: "hidden1" ) << ".ex"  << "ex" ; | 
| 886 |     QTest::newRow(dataTag: "hidden1" ) << ".e"  << "e" ; | 
| 887 |     QTest::newRow(dataTag: "hidden2" ) << ".ext1.ext2"  << "ext2" ; | 
| 888 |     QTest::newRow(dataTag: "hidden2" ) << ".ext.ext2"  << "ext2" ; | 
| 889 |     QTest::newRow(dataTag: "hidden2" ) << ".ex.ext2"  << "ext2" ; | 
| 890 |     QTest::newRow(dataTag: "hidden2" ) << ".e.ext2"  << "ext2" ; | 
| 891 |     QTest::newRow(dataTag: "hidden2" ) << "..ext2"  << "ext2" ; | 
| 892 | #ifdef Q_OS_WIN | 
| 893 |     QTest::newRow("driveWithSlash" ) << "c:/file1.ext1.ext2"  << "ext2" ; | 
| 894 |     QTest::newRow("driveWithoutSlash" ) << "c:file1.ext1.ext2"  << "ext2" ; | 
| 895 | #endif | 
| 896 | } | 
| 897 |  | 
| 898 | void tst_QFileInfo::suffix() | 
| 899 | { | 
| 900 |     QFETCH(QString, file); | 
| 901 |     QFETCH(QString, expected); | 
| 902 |  | 
| 903 |     QFileInfo fi(file); | 
| 904 |     QCOMPARE(fi.suffix(), expected); | 
| 905 | } | 
| 906 |  | 
| 907 |  | 
| 908 | void tst_QFileInfo::completeSuffix_data() | 
| 909 | { | 
| 910 |     QTest::addColumn<QString>(name: "file" ); | 
| 911 |     QTest::addColumn<QString>(name: "expected" ); | 
| 912 |  | 
| 913 |     QTest::newRow(dataTag: "noextension0" ) << "file"  << "" ; | 
| 914 |     QTest::newRow(dataTag: "noextension1" ) << "/path/to/file"  << "" ; | 
| 915 |     QTest::newRow(dataTag: "data0" ) << "file.tar"  << "tar" ; | 
| 916 |     QTest::newRow(dataTag: "data1" ) << "file.tar.gz"  << "tar.gz" ; | 
| 917 |     QTest::newRow(dataTag: "data2" ) << "/path/file/file.tar.gz"  << "tar.gz" ; | 
| 918 |     QTest::newRow(dataTag: "data3" ) << "/path/file.tar"  << "tar" ; | 
| 919 |     QTest::newRow(dataTag: "resource1" ) << ":/tst_qfileinfo/resources/file1.ext1"  << "ext1" ; | 
| 920 |     QTest::newRow(dataTag: "resource2" ) << ":/tst_qfileinfo/resources/file1.ext1.ext2"  << "ext1.ext2" ; | 
| 921 | #ifdef Q_OS_WIN | 
| 922 |     QTest::newRow("driveWithSlash" ) << "c:/file1.ext1.ext2"  << "ext1.ext2" ; | 
| 923 |     QTest::newRow("driveWithoutSlash" ) << "c:file1.ext1.ext2"  << "ext1.ext2" ; | 
| 924 | #endif | 
| 925 | } | 
| 926 |  | 
| 927 | void tst_QFileInfo::completeSuffix() | 
| 928 | { | 
| 929 |     QFETCH(QString, file); | 
| 930 |     QFETCH(QString, expected); | 
| 931 |  | 
| 932 |     QFileInfo fi(file); | 
| 933 |     QCOMPARE(fi.completeSuffix(), expected); | 
| 934 | } | 
| 935 |  | 
| 936 | void tst_QFileInfo::baseName_data() | 
| 937 | { | 
| 938 |     QTest::addColumn<QString>(name: "file" ); | 
| 939 |     QTest::addColumn<QString>(name: "expected" ); | 
| 940 |  | 
| 941 |     QTest::newRow(dataTag: "data0" ) << "file.tar"  << "file" ; | 
| 942 |     QTest::newRow(dataTag: "data1" ) << "file.tar.gz"  << "file" ; | 
| 943 |     QTest::newRow(dataTag: "data2" ) << "/path/file/file.tar.gz"  << "file" ; | 
| 944 |     QTest::newRow(dataTag: "data3" ) << "/path/file.tar"  << "file" ; | 
| 945 |     QTest::newRow(dataTag: "data4" ) << "/path/file"  << "file" ; | 
| 946 |     QTest::newRow(dataTag: "resource1" ) << ":/tst_qfileinfo/resources/file1.ext1"  << "file1" ; | 
| 947 |     QTest::newRow(dataTag: "resource2" ) << ":/tst_qfileinfo/resources/file1.ext1.ext2"  << "file1" ; | 
| 948 | #ifdef Q_OS_WIN | 
| 949 |     QTest::newRow("driveWithSlash" ) << "c:/file1.ext1.ext2"  << "file1" ; | 
| 950 |     QTest::newRow("driveWithoutSlash" ) << "c:file1.ext1.ext2"  << "file1" ; | 
| 951 | #endif | 
| 952 | } | 
| 953 |  | 
| 954 | void tst_QFileInfo::baseName() | 
| 955 | { | 
| 956 |     QFETCH(QString, file); | 
| 957 |     QFETCH(QString, expected); | 
| 958 |  | 
| 959 |     QFileInfo fi(file); | 
| 960 |     QCOMPARE(fi.baseName(), expected); | 
| 961 | } | 
| 962 |  | 
| 963 | void tst_QFileInfo::completeBaseName_data() | 
| 964 | { | 
| 965 |     QTest::addColumn<QString>(name: "file" ); | 
| 966 |     QTest::addColumn<QString>(name: "expected" ); | 
| 967 |  | 
| 968 |     QTest::newRow(dataTag: "data0" ) << "file.tar"  << "file" ; | 
| 969 |     QTest::newRow(dataTag: "data1" ) << "file.tar.gz"  << "file.tar" ; | 
| 970 |     QTest::newRow(dataTag: "data2" ) << "/path/file/file.tar.gz"  << "file.tar" ; | 
| 971 |     QTest::newRow(dataTag: "data3" ) << "/path/file.tar"  << "file" ; | 
| 972 |     QTest::newRow(dataTag: "data4" ) << "/path/file"  << "file" ; | 
| 973 |     QTest::newRow(dataTag: "resource1" ) << ":/tst_qfileinfo/resources/file1.ext1"  << "file1" ; | 
| 974 |     QTest::newRow(dataTag: "resource2" ) << ":/tst_qfileinfo/resources/file1.ext1.ext2"  << "file1.ext1" ; | 
| 975 | #ifdef Q_OS_WIN | 
| 976 |     QTest::newRow("driveWithSlash" ) << "c:/file1.ext1.ext2"  << "file1.ext1" ; | 
| 977 |     QTest::newRow("driveWithoutSlash" ) << "c:file1.ext1.ext2"  << "file1.ext1" ; | 
| 978 | #endif | 
| 979 | } | 
| 980 |  | 
| 981 | void tst_QFileInfo::completeBaseName() | 
| 982 | { | 
| 983 |     QFETCH(QString, file); | 
| 984 |     QFETCH(QString, expected); | 
| 985 |  | 
| 986 |     QFileInfo fi(file); | 
| 987 |     QCOMPARE(fi.completeBaseName(), expected); | 
| 988 | } | 
| 989 |  | 
| 990 | void tst_QFileInfo::permission_data() | 
| 991 | { | 
| 992 |     QTest::addColumn<QString>(name: "file" ); | 
| 993 |     QTest::addColumn<int>(name: "perms" ); | 
| 994 |     QTest::addColumn<bool>(name: "expected" ); | 
| 995 |  | 
| 996 |     QTest::newRow(dataTag: "data0" ) << QCoreApplication::instance()->applicationFilePath() << int(QFile::ExeUser) << true; | 
| 997 |     QTest::newRow(dataTag: "data1" ) << m_sourceFile << int(QFile::ReadUser) << true; | 
| 998 |     QTest::newRow(dataTag: "resource1" ) << ":/tst_qfileinfo/resources/file1.ext1"  << int(QFile::ReadUser) << true; | 
| 999 |     QTest::newRow(dataTag: "resource2" ) << ":/tst_qfileinfo/resources/file1.ext1"  << int(QFile::WriteUser) << false; | 
| 1000 |     QTest::newRow(dataTag: "resource3" ) << ":/tst_qfileinfo/resources/file1.ext1"  << int(QFile::ExeUser) << false; | 
| 1001 | } | 
| 1002 |  | 
| 1003 | void tst_QFileInfo::permission() | 
| 1004 | { | 
| 1005 |     QFETCH(QString, file); | 
| 1006 |     QFETCH(int, perms); | 
| 1007 |     QFETCH(bool, expected); | 
| 1008 |     QFileInfo fi(file); | 
| 1009 |     QCOMPARE(fi.permission(QFile::Permissions(perms)), expected); | 
| 1010 | } | 
| 1011 |  | 
| 1012 | void tst_QFileInfo::size_data() | 
| 1013 | { | 
| 1014 |     QTest::addColumn<QString>(name: "file" ); | 
| 1015 |     QTest::addColumn<int>(name: "size" ); | 
| 1016 |  | 
| 1017 |     QTest::newRow(dataTag: "resource1" ) << ":/tst_qfileinfo/resources/file1.ext1"  << 0; | 
| 1018 |     QFile::remove(fileName: "file1" ); | 
| 1019 |     QFile file("file1" ); | 
| 1020 |     QVERIFY(file.open(QFile::WriteOnly)); | 
| 1021 |     QCOMPARE(file.write("JAJAJAA" ), qint64(7)); | 
| 1022 |     QTest::newRow(dataTag: "created-file" ) << "file1"  << 7; | 
| 1023 |  | 
| 1024 |     QTest::newRow(dataTag: "resource2" ) << ":/tst_qfileinfo/resources/file1.ext1.ext2"  << 0; | 
| 1025 | } | 
| 1026 |  | 
| 1027 | void tst_QFileInfo::size() | 
| 1028 | { | 
| 1029 |     QFETCH(QString, file); | 
| 1030 |  | 
| 1031 |     QFileInfo fi(file); | 
| 1032 |     (void)fi.permissions(); | 
| 1033 |     QTEST(int(fi.size()), "size" ); | 
| 1034 | } | 
| 1035 |  | 
| 1036 | void tst_QFileInfo::systemFiles() | 
| 1037 | { | 
| 1038 | #if !defined(Q_OS_WIN) || defined(Q_OS_WINRT) | 
| 1039 |     QSKIP("This is a Windows only test" ); | 
| 1040 | #endif | 
| 1041 |     QFileInfo fi("c:\\pagefile.sys" ); | 
| 1042 |     QVERIFY2(fi.exists(), msgDoesNotExist(fi.absoluteFilePath()).constData()); | 
| 1043 |     QVERIFY(fi.size() > 0); | 
| 1044 |     QVERIFY(fi.lastModified().isValid()); | 
| 1045 |     QVERIFY(fi.metadataChangeTime().isValid()); | 
| 1046 |     QCOMPARE(fi.metadataChangeTime(), fi.lastModified());   // On Windows, they're the same | 
| 1047 |     QVERIFY(fi.birthTime().isValid()); | 
| 1048 |     QVERIFY(fi.birthTime() <= fi.lastModified()); | 
| 1049 | #if QT_DEPRECATED_SINCE(5, 10) | 
| 1050 |     QCOMPARE(fi.created(), fi.birthTime());                 // On Windows, they're the same | 
| 1051 | #endif | 
| 1052 | } | 
| 1053 |  | 
| 1054 | void tst_QFileInfo::compare_data() | 
| 1055 | { | 
| 1056 |     QTest::addColumn<QString>(name: "file1" ); | 
| 1057 |     QTest::addColumn<QString>(name: "file2" ); | 
| 1058 |     QTest::addColumn<bool>(name: "same" ); | 
| 1059 |  | 
| 1060 |     QString caseChangedSource = m_sourceFile; | 
| 1061 |     caseChangedSource.replace(before: "info" , after: "Info" ); | 
| 1062 |  | 
| 1063 |     QTest::newRow(dataTag: "data0" ) | 
| 1064 |         << m_sourceFile | 
| 1065 |         << m_sourceFile | 
| 1066 |         << true; | 
| 1067 |     QTest::newRow(dataTag: "data1" ) | 
| 1068 |         << m_sourceFile | 
| 1069 |         << QString::fromLatin1(str: "/tst_qfileinfo.cpp" ) | 
| 1070 |         << false; | 
| 1071 |     QTest::newRow(dataTag: "data2" ) | 
| 1072 |         << QString::fromLatin1(str: "tst_qfileinfo.cpp" ) | 
| 1073 |         << QDir::currentPath() + QString::fromLatin1(str: "/tst_qfileinfo.cpp" ) | 
| 1074 |         << true; | 
| 1075 |     QTest::newRow(dataTag: "casesense1" ) | 
| 1076 |         << caseChangedSource | 
| 1077 |         << m_sourceFile | 
| 1078 | #if defined(Q_OS_WIN) | 
| 1079 |         << true; | 
| 1080 | #elif defined(Q_OS_MAC) | 
| 1081 |         << !pathconf(QDir::currentPath().toLatin1().constData(), _PC_CASE_SENSITIVE); | 
| 1082 | #else | 
| 1083 |         << false; | 
| 1084 | #endif | 
| 1085 | } | 
| 1086 |  | 
| 1087 | void tst_QFileInfo::compare() | 
| 1088 | { | 
| 1089 | #if defined(Q_OS_MAC) | 
| 1090 |     if (qstrcmp(QTest::currentDataTag(), "casesense1" ) == 0) | 
| 1091 |         QSKIP("Qt thinks all UNIX filesystems are case sensitive, see QTBUG-28246" ); | 
| 1092 | #endif | 
| 1093 |  | 
| 1094 |     QFETCH(QString, file1); | 
| 1095 |     QFETCH(QString, file2); | 
| 1096 |     QFETCH(bool, same); | 
| 1097 |     QFileInfo fi1(file1), fi2(file2); | 
| 1098 |     QCOMPARE(fi1 == fi2, same); | 
| 1099 | } | 
| 1100 |  | 
| 1101 | void tst_QFileInfo::consistent_data() | 
| 1102 | { | 
| 1103 |     QTest::addColumn<QString>(name: "file" ); | 
| 1104 |     QTest::addColumn<QString>(name: "expected" ); | 
| 1105 |  | 
| 1106 | #if defined(Q_OS_WIN) | 
| 1107 |     QTest::newRow("slashes" ) << QString::fromLatin1("\\a\\a\\a\\a" ) << QString::fromLatin1("/a/a/a/a" ); | 
| 1108 | #endif | 
| 1109 |     QTest::newRow(dataTag: "ending slash" ) << QString::fromLatin1(str: "/a/somedir/" ) << QString::fromLatin1(str: "/a/somedir/" ); | 
| 1110 |     QTest::newRow(dataTag: "no ending slash" ) << QString::fromLatin1(str: "/a/somedir" ) << QString::fromLatin1(str: "/a/somedir" ); | 
| 1111 | } | 
| 1112 |  | 
| 1113 | void tst_QFileInfo::consistent() | 
| 1114 | { | 
| 1115 |     QFETCH(QString, file); | 
| 1116 |     QFETCH(QString, expected); | 
| 1117 |  | 
| 1118 |     QFileInfo fi(file); | 
| 1119 |     QCOMPARE(fi.filePath(), expected); | 
| 1120 |     QCOMPARE(fi.dir().path() + QLatin1Char('/') + fi.fileName(), expected); | 
| 1121 | } | 
| 1122 |  | 
| 1123 |  | 
| 1124 | void tst_QFileInfo::fileTimes_data() | 
| 1125 | { | 
| 1126 |     QTest::addColumn<QString>(name: "fileName" ); | 
| 1127 |     QTest::newRow(dataTag: "simple" ) << QString::fromLatin1(str: "simplefile.txt" ); | 
| 1128 |     QTest::newRow( dataTag: "longfile"  ) << QString::fromLatin1(str: "longFileNamelongFileNamelongFileNamelongFileName"  | 
| 1129 |                                                      "longFileNamelongFileNamelongFileNamelongFileName"  | 
| 1130 |                                                      "longFileNamelongFileNamelongFileNamelongFileName"  | 
| 1131 |                                                      "longFileNamelongFileNamelongFileNamelongFileName"  | 
| 1132 |                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt" ); | 
| 1133 |     QTest::newRow( dataTag: "longfile absolutepath"  ) << QFileInfo(QString::fromLatin1(str: "longFileNamelongFileNamelongFileNamelongFileName"  | 
| 1134 |                                                      "longFileNamelongFileNamelongFileNamelongFileName"  | 
| 1135 |                                                      "longFileNamelongFileNamelongFileNamelongFileName"  | 
| 1136 |                                                      "longFileNamelongFileNamelongFileNamelongFileName"  | 
| 1137 |                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt" )).absoluteFilePath(); | 
| 1138 | } | 
| 1139 |  | 
| 1140 | void tst_QFileInfo::fileTimes() | 
| 1141 | { | 
| 1142 |     auto datePairString = [](const QDateTime &actual, const QDateTime &before) { | 
| 1143 |         return (actual.toString(format: Qt::ISODateWithMs) + " (should be >) "  + before.toString(format: Qt::ISODateWithMs)) | 
| 1144 |                 .toLatin1(); | 
| 1145 |     }; | 
| 1146 |  | 
| 1147 |     QFETCH(QString, fileName); | 
| 1148 |     int sleepTime = 100; | 
| 1149 |  | 
| 1150 |     // on Linux and Windows, the filesystem timestamps may be slightly out of | 
| 1151 |     // sync with the system clock (maybe they're using CLOCK_REALTIME_COARSE), | 
| 1152 |     // so add a margin of error to our comparisons | 
| 1153 |     int fsClockSkew = 10; | 
| 1154 | #ifdef Q_OS_WIN | 
| 1155 |     fsClockSkew = 500; | 
| 1156 | #endif | 
| 1157 |  | 
| 1158 |     // NFS clocks may be WAY out of sync | 
| 1159 |     if (qIsLikelyToBeNfs(path: fileName)) | 
| 1160 |         QSKIP("This test doesn't work on NFS" ); | 
| 1161 |  | 
| 1162 |     bool noAccessTime = false; | 
| 1163 |     { | 
| 1164 |         // try to guess if file times on this filesystem round to the second | 
| 1165 |         QFileInfo cwd("." ); | 
| 1166 |         if (cwd.lastModified().toMSecsSinceEpoch() % 1000 == 0 | 
| 1167 |                 && cwd.lastRead().toMSecsSinceEpoch() % 1000 == 0) { | 
| 1168 |             fsClockSkew = sleepTime = 1000; | 
| 1169 |  | 
| 1170 |             noAccessTime = qIsLikelyToBeFat(path: fileName); | 
| 1171 |             if (noAccessTime) { | 
| 1172 |                 // FAT filesystems (but maybe not exFAT) store timestamps with 2-second | 
| 1173 |                 // granularity and access time with 1-day granularity | 
| 1174 |                 fsClockSkew = sleepTime = 2000; | 
| 1175 |             } | 
| 1176 |         } | 
| 1177 |     } | 
| 1178 |  | 
| 1179 |     if (QFile::exists(fileName)) { | 
| 1180 |         QVERIFY(QFile::remove(fileName)); | 
| 1181 |     } | 
| 1182 |  | 
| 1183 |     QDateTime beforeBirth, beforeWrite, beforeMetadataChange, beforeRead; | 
| 1184 |     QDateTime birthTime, writeTime, metadataChangeTime, readTime; | 
| 1185 |  | 
| 1186 |     // --- Create file and write to it | 
| 1187 |     beforeBirth = QDateTime::currentDateTime().addMSecs(msecs: -fsClockSkew); | 
| 1188 |     { | 
| 1189 |         QFile file(fileName); | 
| 1190 |         QVERIFY(file.open(QFile::WriteOnly | QFile::Text)); | 
| 1191 |         QFileInfo fileInfo(fileName); | 
| 1192 |         birthTime = fileInfo.birthTime(); | 
| 1193 |         QVERIFY2(!birthTime.isValid() || birthTime > beforeBirth, | 
| 1194 |                  datePairString(birthTime, beforeBirth)); | 
| 1195 |  | 
| 1196 |         QTest::qSleep(ms: sleepTime); | 
| 1197 |         beforeWrite = QDateTime::currentDateTime().addMSecs(msecs: -fsClockSkew); | 
| 1198 |         QTextStream ts(&file); | 
| 1199 |         ts << fileName << Qt::endl; | 
| 1200 |     } | 
| 1201 |     { | 
| 1202 |         QFileInfo fileInfo(fileName); | 
| 1203 |         writeTime = fileInfo.lastModified(); | 
| 1204 |         QVERIFY2(writeTime > beforeWrite, datePairString(writeTime, beforeWrite)); | 
| 1205 |         QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed | 
| 1206 |     } | 
| 1207 |  | 
| 1208 |     // --- Change the file's metadata | 
| 1209 |     QTest::qSleep(ms: sleepTime); | 
| 1210 |     beforeMetadataChange = QDateTime::currentDateTime().addMSecs(msecs: -fsClockSkew); | 
| 1211 |     { | 
| 1212 |         QFile file(fileName); | 
| 1213 |         file.setPermissions(file.permissions()); | 
| 1214 |     } | 
| 1215 |     { | 
| 1216 |         QFileInfo fileInfo(fileName); | 
| 1217 |         metadataChangeTime = fileInfo.metadataChangeTime(); | 
| 1218 |         QVERIFY2(metadataChangeTime > beforeMetadataChange, | 
| 1219 |                  datePairString(metadataChangeTime, beforeMetadataChange)); | 
| 1220 |         QVERIFY(metadataChangeTime >= writeTime); // not all filesystems can store both times | 
| 1221 |         QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed | 
| 1222 |     } | 
| 1223 |  | 
| 1224 |     // --- Read the file | 
| 1225 |     QTest::qSleep(ms: sleepTime); | 
| 1226 |     beforeRead = QDateTime::currentDateTime().addMSecs(msecs: -fsClockSkew); | 
| 1227 |     { | 
| 1228 |         QFile file(fileName); | 
| 1229 |         QVERIFY(file.open(QFile::ReadOnly | QFile::Text)); | 
| 1230 |         QTextStream ts(&file); | 
| 1231 |         QString line = ts.readLine(); | 
| 1232 |         QCOMPARE(line, fileName); | 
| 1233 |     } | 
| 1234 |  | 
| 1235 |     QFileInfo fileInfo(fileName); | 
| 1236 |     readTime = fileInfo.lastRead(); | 
| 1237 |     QCOMPARE(fileInfo.lastModified(), writeTime); // mustn't have changed | 
| 1238 |     QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed | 
| 1239 |     QVERIFY(readTime.isValid()); | 
| 1240 |  | 
| 1241 | #if defined(Q_OS_WINRT) || defined(Q_OS_QNX) || (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)) | 
| 1242 |     noAccessTime = true; | 
| 1243 | #elif defined(Q_OS_WIN) | 
| 1244 |     //In Vista the last-access timestamp is not updated when the file is accessed/touched (by default). | 
| 1245 |     //To enable this the HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate | 
| 1246 |     //is set to 0, in the test machine. | 
| 1247 |     const auto disabledAccessTimes = | 
| 1248 |         QWinRegistryKey(HKEY_LOCAL_MACHINE, | 
| 1249 |                         LR"(SYSTEM\CurrentControlSet\Control\FileSystem)" ) | 
| 1250 |         .dwordValue(L"NtfsDisableLastAccessUpdate" ); | 
| 1251 |     if (disabledAccessTimes.second && disabledAccessTimes.first != 0) | 
| 1252 |         noAccessTime = true; | 
| 1253 | #endif | 
| 1254 |  | 
| 1255 |     if (noAccessTime) | 
| 1256 |         return; | 
| 1257 |  | 
| 1258 |     QVERIFY2(readTime > beforeRead, datePairString(readTime, beforeRead)); | 
| 1259 |     QVERIFY(writeTime < beforeRead); | 
| 1260 | } | 
| 1261 |  | 
| 1262 | void tst_QFileInfo::fakeFileTimes_data() | 
| 1263 | { | 
| 1264 |     QTest::addColumn<QDateTime>(name: "when" ); | 
| 1265 |  | 
| 1266 |     // This is 2^{31} seconds before 1970-01-01 15:14:8, | 
| 1267 |     // i.e. shortly after the start of time_t, in any time-zone: | 
| 1268 |     QTest::newRow(dataTag: "early" ) << QDateTime(QDate(1901, 12, 14), QTime(12, 0)); | 
| 1269 |  | 
| 1270 |     // QTBUG-12006 claims XP handled this (2010-Mar-26 8:46:10) wrong due to an MS API bug: | 
| 1271 |     QTest::newRow(dataTag: "XP-bug" ) << QDateTime::fromSecsSinceEpoch(secs: 1269593170); | 
| 1272 | } | 
| 1273 |  | 
| 1274 | void tst_QFileInfo::fakeFileTimes() | 
| 1275 | { | 
| 1276 |     QFETCH(QDateTime, when); | 
| 1277 |  | 
| 1278 |     QFile file("faketimefile.txt" ); | 
| 1279 |     file.open(flags: QIODevice::WriteOnly); | 
| 1280 |     file.write(data: "\n" , len: 1); | 
| 1281 |     file.close(); | 
| 1282 |  | 
| 1283 |     /* | 
| 1284 |       QFile's setFileTime calls QFSFileEngine::setFileTime() which fails unless | 
| 1285 |       the file is open at the time.  Of course, when writing, close() changes | 
| 1286 |       modification time, so need to re-open for read in order to setFileTime(). | 
| 1287 |      */ | 
| 1288 |     file.open(flags: QIODevice::ReadOnly); | 
| 1289 |     bool ok = file.setFileTime(newDate: when, fileTime: QFileDevice::FileModificationTime); | 
| 1290 |     file.close(); | 
| 1291 |  | 
| 1292 |     if (ok) | 
| 1293 |         QCOMPARE(QFileInfo(file.fileName()).lastModified(), when); | 
| 1294 |     else | 
| 1295 |         QSKIP("Unable to set file metadata to contrived values" ); | 
| 1296 | } | 
| 1297 |  | 
| 1298 | void tst_QFileInfo::isSymLink_data() | 
| 1299 | { | 
| 1300 | #ifndef Q_NO_SYMLINKS | 
| 1301 |     QFile::remove(fileName: "link.lnk" ); | 
| 1302 |     QFile::remove(fileName: "brokenlink.lnk" ); | 
| 1303 |     QFile::remove(fileName: "dummyfile" ); | 
| 1304 |     QFile::remove(fileName: "relative/link.lnk" ); | 
| 1305 |  | 
| 1306 |     QFile file1(m_sourceFile); | 
| 1307 |     QVERIFY(file1.link("link.lnk" )); | 
| 1308 |  | 
| 1309 |     QFile file2("dummyfile" ); | 
| 1310 |     file2.open(flags: QIODevice::WriteOnly); | 
| 1311 |     QVERIFY(file2.link("brokenlink.lnk" )); | 
| 1312 |     file2.remove(); | 
| 1313 |  | 
| 1314 |     QTest::addColumn<QString>(name: "path" ); | 
| 1315 |     QTest::addColumn<bool>(name: "isSymLink" ); | 
| 1316 |     QTest::addColumn<QString>(name: "linkTarget" ); | 
| 1317 |  | 
| 1318 |     QTest::newRow(dataTag: "existent file" ) << m_sourceFile << false << "" ; | 
| 1319 |     QTest::newRow(dataTag: "link" ) << "link.lnk"  << true << QFileInfo(m_sourceFile).absoluteFilePath(); | 
| 1320 |     QTest::newRow(dataTag: "broken link" ) << "brokenlink.lnk"  << true << QFileInfo("dummyfile" ).absoluteFilePath(); | 
| 1321 |  | 
| 1322 | #ifndef Q_OS_WIN | 
| 1323 |     QDir::current().mkdir(dirName: "relative" ); | 
| 1324 |     QFile::link(oldname: "../dummyfile" , newName: "relative/link.lnk" ); | 
| 1325 |     QTest::newRow(dataTag: "relative link" ) << "relative/link.lnk"  << true << QFileInfo("dummyfile" ).absoluteFilePath(); | 
| 1326 | #endif | 
| 1327 | #endif | 
| 1328 | } | 
| 1329 |  | 
| 1330 | void tst_QFileInfo::isSymLink() | 
| 1331 | { | 
| 1332 | #ifdef Q_NO_SYMLINKS | 
| 1333 |     QSKIP("No symlink support" , SkipAll); | 
| 1334 | #else | 
| 1335 |     QFETCH(QString, path); | 
| 1336 |     QFETCH(bool, isSymLink); | 
| 1337 |     QFETCH(QString, linkTarget); | 
| 1338 |  | 
| 1339 |     QFileInfo fi(path); | 
| 1340 |     QCOMPARE(fi.isSymLink(), isSymLink); | 
| 1341 |     QCOMPARE(fi.symLinkTarget(), linkTarget); | 
| 1342 | #endif | 
| 1343 | } | 
| 1344 |  | 
| 1345 | void tst_QFileInfo::isShortcut_data() | 
| 1346 | { | 
| 1347 |     QFile::remove(fileName: "link.lnk" ); | 
| 1348 |     QFile::remove(fileName: "symlink.lnk" ); | 
| 1349 |     QFile::remove(fileName: "link" ); | 
| 1350 |     QFile::remove(fileName: "symlink" ); | 
| 1351 |     QFile::remove(fileName: "directory.lnk" ); | 
| 1352 |     QFile::remove(fileName: "directory" ); | 
| 1353 |  | 
| 1354 |     QTest::addColumn<QString>(name: "path" ); | 
| 1355 |     QTest::addColumn<bool>(name: "isShortcut" ); | 
| 1356 |  | 
| 1357 |     QFile regularFile(m_sourceFile); | 
| 1358 |     QTest::newRow(dataTag: "regular" ) | 
| 1359 |         << regularFile.fileName() << false; | 
| 1360 |     QTest::newRow(dataTag: "directory" ) | 
| 1361 |         << QDir::currentPath() << false; | 
| 1362 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 1363 |     // windows shortcuts | 
| 1364 |     QVERIFY(regularFile.link("link.lnk" )); | 
| 1365 |     QTest::newRow("shortcut" ) | 
| 1366 |         << "link.lnk"  << true; | 
| 1367 |     QVERIFY(regularFile.link("link" )); | 
| 1368 |     QTest::newRow("invalid-shortcut" ) | 
| 1369 |         << "link"  << false; | 
| 1370 |     QVERIFY(QFile::link(QDir::currentPath(), "directory.lnk" )); | 
| 1371 |     QTest::newRow("directory-shortcut" ) | 
| 1372 |         << "directory.lnk"  << true; | 
| 1373 | #endif | 
| 1374 | } | 
| 1375 |  | 
| 1376 | void tst_QFileInfo::isShortcut() | 
| 1377 | { | 
| 1378 |     QFETCH(QString, path); | 
| 1379 |     QFETCH(bool, isShortcut); | 
| 1380 |  | 
| 1381 |     QFileInfo fi(path); | 
| 1382 |     QCOMPARE(fi.isShortcut(), isShortcut); | 
| 1383 | } | 
| 1384 |  | 
| 1385 | void tst_QFileInfo::isSymbolicLink_data() | 
| 1386 | { | 
| 1387 |     QTest::addColumn<QString>(name: "path" ); | 
| 1388 |     QTest::addColumn<bool>(name: "isSymbolicLink" ); | 
| 1389 |  | 
| 1390 |     QFile regularFile(m_sourceFile); | 
| 1391 |     QTest::newRow(dataTag: "regular" ) | 
| 1392 |         << regularFile.fileName() << false; | 
| 1393 |     QTest::newRow(dataTag: "directory" ) | 
| 1394 |         << QDir::currentPath() << false; | 
| 1395 |  | 
| 1396 | #ifndef Q_NO_SYMLINKS | 
| 1397 | #if defined(Q_OS_WIN) | 
| 1398 | #if !defined(Q_OS_WINRT) | 
| 1399 |     QString errorMessage; | 
| 1400 |     const DWORD creationResult = createSymbolicLink("symlink" , m_sourceFile, &errorMessage); | 
| 1401 |     if (creationResult == ERROR_PRIVILEGE_NOT_HELD) { | 
| 1402 |         QWARN(msgInsufficientPrivileges(errorMessage)); | 
| 1403 |     } else { | 
| 1404 |         QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage)); | 
| 1405 |         QTest::newRow("NTFS-symlink" ) | 
| 1406 |             << "symlink"  << true; | 
| 1407 |     } | 
| 1408 | #endif // !Q_OS_WINRT | 
| 1409 | #else // Unix: | 
| 1410 |     QVERIFY(regularFile.link("symlink.lnk" )); | 
| 1411 |     QTest::newRow(dataTag: "symlink.lnk" ) | 
| 1412 |         << "symlink.lnk"  << true; | 
| 1413 |     QVERIFY(regularFile.link("symlink" )); | 
| 1414 |     QTest::newRow(dataTag: "symlink" ) | 
| 1415 |         << "symlink"  << true; | 
| 1416 |     QVERIFY(QFile::link(QDir::currentPath(), "directory" )); | 
| 1417 |     QTest::newRow(dataTag: "directory-symlink" ) | 
| 1418 |         << "directory"  << true; | 
| 1419 | #endif | 
| 1420 | #endif // !Q_NO_SYMLINKS | 
| 1421 | } | 
| 1422 |  | 
| 1423 | void tst_QFileInfo::isSymbolicLink() | 
| 1424 | { | 
| 1425 |     QFETCH(QString, path); | 
| 1426 |     QFETCH(bool, isSymbolicLink); | 
| 1427 |  | 
| 1428 |     QFileInfo fi(path); | 
| 1429 |     QCOMPARE(fi.isSymbolicLink(), isSymbolicLink); | 
| 1430 | } | 
| 1431 |  | 
| 1432 | void tst_QFileInfo::link_data() | 
| 1433 | { | 
| 1434 |     QFile::remove(fileName: "link" ); | 
| 1435 |     QFile::remove(fileName: "link.lnk" ); | 
| 1436 |     QFile::remove(fileName: "brokenlink" ); | 
| 1437 |     QFile::remove(fileName: "brokenlink.lnk" ); | 
| 1438 |     QFile::remove(fileName: "dummyfile" ); | 
| 1439 |     QFile::remove(fileName: "relative/link" ); | 
| 1440 |  | 
| 1441 |     QTest::addColumn<QString>(name: "path" ); | 
| 1442 |     QTest::addColumn<bool>(name: "isShortcut" ); | 
| 1443 |     QTest::addColumn<bool>(name: "isSymbolicLink" ); | 
| 1444 |     QTest::addColumn<QString>(name: "linkTarget" ); | 
| 1445 |  | 
| 1446 |     QFile file1(m_sourceFile); | 
| 1447 |     QFile file2("dummyfile" ); | 
| 1448 |     file2.open(flags: QIODevice::WriteOnly); | 
| 1449 |  | 
| 1450 |     QTest::newRow(dataTag: "existent file" ) << m_sourceFile << false << false << "" ; | 
| 1451 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 1452 |     // windows shortcuts | 
| 1453 |     QVERIFY(file1.link("link.lnk" )); | 
| 1454 |     QTest::newRow("link.lnk" ) | 
| 1455 |         << "link.lnk"  << true << false << QFileInfo(m_sourceFile).absoluteFilePath(); | 
| 1456 |  | 
| 1457 |     QVERIFY(file2.link("brokenlink.lnk" )); | 
| 1458 |     QTest::newRow("broken link.lnk" ) | 
| 1459 |         << "brokenlink.lnk"  << true << false << QFileInfo("dummyfile" ).absoluteFilePath(); | 
| 1460 | #endif | 
| 1461 |  | 
| 1462 | #ifndef Q_NO_SYMLINKS | 
| 1463 | #if defined(Q_OS_WIN) | 
| 1464 | #if !defined(Q_OS_WINRT) | 
| 1465 |     QString errorMessage; | 
| 1466 |     DWORD creationResult = createSymbolicLink("link" , m_sourceFile, &errorMessage); | 
| 1467 |     if (creationResult == ERROR_PRIVILEGE_NOT_HELD) { | 
| 1468 |         QWARN(msgInsufficientPrivileges(errorMessage)); | 
| 1469 |     } else { | 
| 1470 |         QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage)); | 
| 1471 |         QTest::newRow("link" ) | 
| 1472 |             << "link"  << false << true << QFileInfo(m_sourceFile).absoluteFilePath(); | 
| 1473 |     } | 
| 1474 |  | 
| 1475 |     creationResult = createSymbolicLink("brokenlink" , "dummyfile" , &errorMessage); | 
| 1476 |     if (creationResult == ERROR_PRIVILEGE_NOT_HELD) { | 
| 1477 |         QWARN(msgInsufficientPrivileges(errorMessage)); | 
| 1478 |     } else { | 
| 1479 |         QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage)); | 
| 1480 |         QTest::newRow("broken link" ) | 
| 1481 |             << "brokenlink"  << false << true  << QFileInfo("dummyfile" ).absoluteFilePath(); | 
| 1482 |     } | 
| 1483 | #endif // !Q_OS_WINRT | 
| 1484 | #else // Unix: | 
| 1485 |     QVERIFY(file1.link("link" )); | 
| 1486 |     QTest::newRow(dataTag: "link" ) | 
| 1487 |         << "link"  << false << true << QFileInfo(m_sourceFile).absoluteFilePath(); | 
| 1488 |  | 
| 1489 |     QVERIFY(file2.link("brokenlink" )); | 
| 1490 |     QTest::newRow(dataTag: "broken link" ) | 
| 1491 |         << "brokenlink"  << false << true << QFileInfo("dummyfile" ).absoluteFilePath(); | 
| 1492 |  | 
| 1493 |     QDir::current().mkdir(dirName: "relative" ); | 
| 1494 |     QFile::link(oldname: "../dummyfile" , newName: "relative/link" ); | 
| 1495 |     QTest::newRow(dataTag: "relative link" ) | 
| 1496 |         << "relative/link"  << false << true << QFileInfo("dummyfile" ).absoluteFilePath(); | 
| 1497 | #endif | 
| 1498 | #endif // !Q_NO_SYMLINKS | 
| 1499 |     file2.remove(); | 
| 1500 | } | 
| 1501 |  | 
| 1502 | void tst_QFileInfo::link() | 
| 1503 | { | 
| 1504 |     QFETCH(QString, path); | 
| 1505 |     QFETCH(bool, isShortcut); | 
| 1506 |     QFETCH(bool, isSymbolicLink); | 
| 1507 |     QFETCH(QString, linkTarget); | 
| 1508 |  | 
| 1509 |     QFileInfo fi(path); | 
| 1510 |     QCOMPARE(fi.isShortcut(), isShortcut); | 
| 1511 |     QCOMPARE(fi.isSymbolicLink(), isSymbolicLink); | 
| 1512 |     QCOMPARE(fi.symLinkTarget(), linkTarget); | 
| 1513 | } | 
| 1514 |  | 
| 1515 | void tst_QFileInfo::isHidden_data() | 
| 1516 | { | 
| 1517 |     QTest::addColumn<QString>(name: "path" ); | 
| 1518 |     QTest::addColumn<bool>(name: "isHidden" ); | 
| 1519 |     foreach (const QFileInfo& info, QDir::drives()) { | 
| 1520 |         QTest::newRow(qPrintable("drive."  + info.path())) << info.path() << false; | 
| 1521 |     } | 
| 1522 |  | 
| 1523 | #if defined(Q_OS_WIN) | 
| 1524 |     QVERIFY(QDir("./hidden-directory" ).exists() || QDir().mkdir("./hidden-directory" )); | 
| 1525 |     QVERIFY(SetFileAttributesW(reinterpret_cast<LPCWSTR>(QString("./hidden-directory" ).utf16()),FILE_ATTRIBUTE_HIDDEN)); | 
| 1526 |     QTest::newRow("C:/path/to/hidden-directory" ) << QDir::currentPath() + QString::fromLatin1("/hidden-directory" ) << true; | 
| 1527 |     QTest::newRow("C:/path/to/hidden-directory/." ) << QDir::currentPath() + QString::fromLatin1("/hidden-directory/." ) << true; | 
| 1528 | #endif | 
| 1529 | #if defined(Q_OS_UNIX) | 
| 1530 |     QVERIFY(QDir("./.hidden-directory" ).exists() || QDir().mkdir("./.hidden-directory" )); | 
| 1531 |     QTest::newRow(dataTag: "/path/to/.hidden-directory" ) << QDir::currentPath() + QString("/.hidden-directory" ) << true; | 
| 1532 |     QTest::newRow(dataTag: "/path/to/.hidden-directory/." ) << QDir::currentPath() + QString("/.hidden-directory/." ) << true; | 
| 1533 |     QTest::newRow(dataTag: "/path/to/.hidden-directory/.." ) << QDir::currentPath() + QString("/.hidden-directory/.." ) << true; | 
| 1534 | #endif | 
| 1535 |  | 
| 1536 | #if defined(Q_OS_MAC) | 
| 1537 |     // /bin has the hidden attribute on OS X | 
| 1538 |     QTest::newRow("/bin/" ) << QString::fromLatin1("/bin/" ) << true; | 
| 1539 | #elif !defined(Q_OS_WIN) | 
| 1540 |     QTest::newRow(dataTag: "/bin/" ) << QString::fromLatin1(str: "/bin/" ) << false; | 
| 1541 | #endif | 
| 1542 |  | 
| 1543 | #ifdef Q_OS_MAC | 
| 1544 |     QTest::newRow("mac_etc" ) << QString::fromLatin1("/etc" ) << true; | 
| 1545 |     QTest::newRow("mac_private_etc" ) << QString::fromLatin1("/private/etc" ) << false; | 
| 1546 |     QTest::newRow("mac_Applications" ) << QString::fromLatin1("/Applications" ) << false; | 
| 1547 | #endif | 
| 1548 | } | 
| 1549 |  | 
| 1550 | void tst_QFileInfo::isHidden() | 
| 1551 | { | 
| 1552 |     QFETCH(QString, path); | 
| 1553 |     QFETCH(bool, isHidden); | 
| 1554 |     QFileInfo fi(path); | 
| 1555 |  | 
| 1556 |     QCOMPARE(fi.isHidden(), isHidden); | 
| 1557 | } | 
| 1558 |  | 
| 1559 | #if defined(Q_OS_MAC) | 
| 1560 | void tst_QFileInfo::isHiddenFromFinder() | 
| 1561 | { | 
| 1562 |     const char *filename = "test_foobar.txt" ; | 
| 1563 |  | 
| 1564 |     QFile testFile(filename); | 
| 1565 |     testFile.open(QIODevice::WriteOnly | QIODevice::Append); | 
| 1566 |     testFile.write(QByteArray("world" )); | 
| 1567 |     testFile.close(); | 
| 1568 |  | 
| 1569 |     struct stat buf; | 
| 1570 |     stat(filename, &buf); | 
| 1571 |     chflags(filename, buf.st_flags | UF_HIDDEN); | 
| 1572 |  | 
| 1573 |     QFileInfo fi(filename); | 
| 1574 |     QCOMPARE(fi.isHidden(), true); | 
| 1575 |  | 
| 1576 |     testFile.remove(); | 
| 1577 | } | 
| 1578 | #endif | 
| 1579 |  | 
| 1580 | void tst_QFileInfo::isBundle_data() | 
| 1581 | { | 
| 1582 |     QTest::addColumn<QString>(name: "path" ); | 
| 1583 |     QTest::addColumn<bool>(name: "isBundle" ); | 
| 1584 |     QTest::newRow(dataTag: "root" ) << QString::fromLatin1(str: "/" ) << false; | 
| 1585 | #ifdef Q_OS_MAC | 
| 1586 |     QTest::newRow("mac_Applications" ) << QString::fromLatin1("/Applications" ) << false; | 
| 1587 |     QTest::newRow("mac_Applications" ) << QString::fromLatin1("/Applications/Safari.app" ) << true; | 
| 1588 | #endif | 
| 1589 | } | 
| 1590 |  | 
| 1591 | void tst_QFileInfo::isBundle() | 
| 1592 | { | 
| 1593 |     QFETCH(QString, path); | 
| 1594 |     QFETCH(bool, isBundle); | 
| 1595 |     QFileInfo fi(path); | 
| 1596 |     QCOMPARE(fi.isBundle(), isBundle); | 
| 1597 | } | 
| 1598 |  | 
| 1599 | void tst_QFileInfo::isNativePath_data() | 
| 1600 | { | 
| 1601 |     QTest::addColumn<QString>(name: "path" ); | 
| 1602 |     QTest::addColumn<bool>(name: "isNativePath" ); | 
| 1603 |  | 
| 1604 |     QTest::newRow(dataTag: "default-constructed" ) << QString() << false; | 
| 1605 |     QTest::newRow(dataTag: "empty" ) << QString("" ) << false; | 
| 1606 |  | 
| 1607 |     QTest::newRow(dataTag: "local root" ) << QString::fromLatin1(str: "/" ) << true; | 
| 1608 |     QTest::newRow(dataTag: "local non-existent file" ) << QString::fromLatin1(str: "/abrakadabra.boo" ) << true; | 
| 1609 |  | 
| 1610 |     QTest::newRow(dataTag: "qresource root" ) << QString::fromLatin1(str: ":/" ) << false; | 
| 1611 | } | 
| 1612 |  | 
| 1613 | void tst_QFileInfo::isNativePath() | 
| 1614 | { | 
| 1615 |     QFETCH(QString, path); | 
| 1616 |     QFETCH(bool, isNativePath); | 
| 1617 |  | 
| 1618 |     QFileInfo info(path); | 
| 1619 |     if (path.isNull()) | 
| 1620 |         info = QFileInfo(); | 
| 1621 |     QCOMPARE(info.isNativePath(), isNativePath); | 
| 1622 | } | 
| 1623 |  | 
| 1624 | void tst_QFileInfo::refresh() | 
| 1625 | { | 
| 1626 | #if defined(Q_OS_WIN) | 
| 1627 |     int sleepTime = 3000; | 
| 1628 | #else | 
| 1629 |     int sleepTime = 2000; | 
| 1630 | #endif | 
| 1631 |  | 
| 1632 |     QFile::remove(fileName: "file1" ); | 
| 1633 |     QFile file("file1" ); | 
| 1634 |     QVERIFY(file.open(QFile::WriteOnly)); | 
| 1635 |     QCOMPARE(file.write("JAJAJAA" ), qint64(7)); | 
| 1636 |     file.flush(); | 
| 1637 |  | 
| 1638 |     QFileInfo info(file); | 
| 1639 |     QDateTime lastModified = info.lastModified(); | 
| 1640 |     QCOMPARE(info.size(), qint64(7)); | 
| 1641 |  | 
| 1642 |     QTest::qSleep(ms: sleepTime); | 
| 1643 |  | 
| 1644 |     QCOMPARE(file.write("JOJOJO" ), qint64(6)); | 
| 1645 |     file.flush(); | 
| 1646 |     QCOMPARE(info.lastModified(), lastModified); | 
| 1647 |  | 
| 1648 |     QCOMPARE(info.size(), qint64(7)); | 
| 1649 | #if defined(Q_OS_WIN) | 
| 1650 |     file.close(); | 
| 1651 | #endif | 
| 1652 |     info.refresh(); | 
| 1653 |     QCOMPARE(info.size(), qint64(13)); | 
| 1654 |     QVERIFY(info.lastModified() > lastModified); | 
| 1655 |  | 
| 1656 |     QFileInfo info2 = info; | 
| 1657 |     QCOMPARE(info2.size(), info.size()); | 
| 1658 |  | 
| 1659 |     info2.refresh(); | 
| 1660 |     QCOMPARE(info2.size(), info.size()); | 
| 1661 | } | 
| 1662 |  | 
| 1663 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 1664 |  | 
| 1665 | struct NtfsTestResource { | 
| 1666 |  | 
| 1667 |     enum Type { None, SymLink, Junction }; | 
| 1668 |  | 
| 1669 |     explicit NtfsTestResource(Type tp = None, const QString &s = QString(), const QString &t = QString()) | 
| 1670 |         : source(s), target(t), type(tp) {} | 
| 1671 |  | 
| 1672 |     QString source; | 
| 1673 |     QString target; | 
| 1674 |     Type type; | 
| 1675 | }; | 
| 1676 |  | 
| 1677 | Q_DECLARE_METATYPE(NtfsTestResource) | 
| 1678 |  | 
| 1679 | void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() | 
| 1680 | { | 
| 1681 |     QTest::addColumn<NtfsTestResource>("resource" ); | 
| 1682 |     QTest::addColumn<QString>("path" ); | 
| 1683 |     QTest::addColumn<bool>("isSymLink" ); | 
| 1684 |     QTest::addColumn<QString>("linkTarget" ); | 
| 1685 |     QTest::addColumn<QString>("canonicalFilePath" ); | 
| 1686 |  | 
| 1687 |     QDir pwd; | 
| 1688 |     pwd.mkdir("target" ); | 
| 1689 |  | 
| 1690 |     { | 
| 1691 |         //Directory symlinks | 
| 1692 |         QDir target("target" ); | 
| 1693 |         QVERIFY(target.exists()); | 
| 1694 |  | 
| 1695 |         QString absTarget = QDir::toNativeSeparators(target.absolutePath()); | 
| 1696 |         QString absSymlink = QDir::toNativeSeparators(pwd.absolutePath()).append("\\abs_symlink" ); | 
| 1697 |         QString relTarget = "target" ; | 
| 1698 |         QString relSymlink = "rel_symlink" ; | 
| 1699 |         QString fileInTarget(absTarget); | 
| 1700 |         fileInTarget.append("\\file" ); | 
| 1701 |         QString fileInSymlink(absSymlink); | 
| 1702 |         fileInSymlink.append("\\file" ); | 
| 1703 |         QFile file(fileInTarget); | 
| 1704 |         QVERIFY2(file.open(QIODevice::ReadWrite), qPrintable(file.errorString())); | 
| 1705 |         file.close(); | 
| 1706 |  | 
| 1707 |         QVERIFY2(file.exists(), msgDoesNotExist(file.fileName()).constData()); | 
| 1708 |  | 
| 1709 |         QTest::newRow("absolute dir symlink" ) | 
| 1710 |             << NtfsTestResource(NtfsTestResource::SymLink, absSymlink, absTarget) | 
| 1711 |             << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalPath(); | 
| 1712 |         QTest::newRow("relative dir symlink" ) | 
| 1713 |             << NtfsTestResource(NtfsTestResource::SymLink, relSymlink, relTarget) | 
| 1714 |             << relSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalPath(); | 
| 1715 |         QTest::newRow("file in symlink dir" ) | 
| 1716 |             << NtfsTestResource() | 
| 1717 |             << fileInSymlink << false << ""  << target.canonicalPath().append("/file" ); | 
| 1718 |     } | 
| 1719 |     { | 
| 1720 |         //File symlinks | 
| 1721 |         pwd.mkdir("relative" ); | 
| 1722 |         QDir relativeDir("relative" ); | 
| 1723 |         QFileInfo target(m_sourceFile); | 
| 1724 |         QString absTarget = QDir::toNativeSeparators(target.absoluteFilePath()); | 
| 1725 |         QString absSymlink = QDir::toNativeSeparators(pwd.absolutePath()).append("\\abs_symlink.cpp" ); | 
| 1726 |         QString relTarget = QDir::toNativeSeparators(pwd.relativeFilePath(target.absoluteFilePath())); | 
| 1727 |         QString relSymlink = "rel_symlink.cpp" ; | 
| 1728 |         QString relToRelTarget = QDir::toNativeSeparators(relativeDir.relativeFilePath(target.absoluteFilePath())); | 
| 1729 |         QString relToRelSymlink = "relative/rel_symlink" ; | 
| 1730 |  | 
| 1731 |         QTest::newRow("absolute file symlink" ) | 
| 1732 |             << NtfsTestResource(NtfsTestResource::SymLink, absSymlink, absTarget) | 
| 1733 |             << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); | 
| 1734 |         QTest::newRow("relative file symlink" ) | 
| 1735 |             << NtfsTestResource(NtfsTestResource::SymLink, relSymlink, relTarget) | 
| 1736 |             << relSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); | 
| 1737 |         QTest::newRow("relative to relative file symlink" ) | 
| 1738 |             << NtfsTestResource(NtfsTestResource::SymLink, relToRelSymlink, relToRelTarget) | 
| 1739 |             << relToRelSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); | 
| 1740 |     } | 
| 1741 |     { | 
| 1742 |         // Symlink to UNC share | 
| 1743 |         pwd.mkdir("unc" ); | 
| 1744 |         QString errorMessage; | 
| 1745 |         QString uncTarget = QStringLiteral("//" ) + QtNetworkSettings::winServerName() + "/testshare" ; | 
| 1746 |         QString uncSymlink = QDir::toNativeSeparators(pwd.absolutePath().append("\\unc\\link_to_unc" )); | 
| 1747 |         QTest::newRow("UNC symlink" ) | 
| 1748 |             << NtfsTestResource(NtfsTestResource::SymLink, uncSymlink, uncTarget) | 
| 1749 |             << QDir::fromNativeSeparators(uncSymlink) << true << QDir::fromNativeSeparators(uncTarget) << uncTarget; | 
| 1750 |     } | 
| 1751 |  | 
| 1752 |     //Junctions | 
| 1753 |     QString target = "target" ; | 
| 1754 |     QString junction = "junction_pwd" ; | 
| 1755 |     QFileInfo targetInfo(target); | 
| 1756 |     QTest::newRow("junction_pwd" ) | 
| 1757 |         << NtfsTestResource(NtfsTestResource::Junction, junction, target) | 
| 1758 |         << junction << false << QString() << QString(); | 
| 1759 |  | 
| 1760 |     QFileInfo fileInJunction(targetInfo.absoluteFilePath().append("/file" )); | 
| 1761 |     QFile file(fileInJunction.absoluteFilePath()); | 
| 1762 |     QVERIFY2(file.open(QIODevice::ReadWrite), qPrintable(file.errorString())); | 
| 1763 |     file.close(); | 
| 1764 |     QVERIFY2(file.exists(), msgDoesNotExist(file.fileName()).constData()); | 
| 1765 |     QTest::newRow("file in junction" ) | 
| 1766 |         << NtfsTestResource() | 
| 1767 |         << fileInJunction.absoluteFilePath() << false << QString() << fileInJunction.canonicalFilePath(); | 
| 1768 |  | 
| 1769 |     target = QDir::rootPath(); | 
| 1770 |     junction = "junction_root" ; | 
| 1771 |     targetInfo.setFile(target); | 
| 1772 |     QTest::newRow("junction_root" ) | 
| 1773 |         << NtfsTestResource(NtfsTestResource::Junction, junction, target) | 
| 1774 |         << junction << false << QString() << QString(); | 
| 1775 |  | 
| 1776 |     //Mountpoint | 
| 1777 |     wchar_t buffer[MAX_PATH]; | 
| 1778 |     QString rootPath = QDir::toNativeSeparators(QDir::rootPath()); | 
| 1779 |     QVERIFY(GetVolumeNameForVolumeMountPoint((wchar_t*)rootPath.utf16(), buffer, MAX_PATH)); | 
| 1780 |     QString rootVolume = QString::fromWCharArray(buffer); | 
| 1781 |     junction = "mountpoint" ; | 
| 1782 |     rootVolume.replace("\\\\?\\" ,"\\??\\" ); | 
| 1783 |     QTest::newRow("mountpoint" ) | 
| 1784 |         << NtfsTestResource(NtfsTestResource::Junction, junction, rootVolume) | 
| 1785 |         << junction << false << QString() << QString(); | 
| 1786 | } | 
| 1787 |  | 
| 1788 | void tst_QFileInfo::ntfsJunctionPointsAndSymlinks() | 
| 1789 | { | 
| 1790 |     QFETCH(NtfsTestResource, resource); | 
| 1791 |     QFETCH(QString, path); | 
| 1792 |     QFETCH(bool, isSymLink); | 
| 1793 |     QFETCH(QString, linkTarget); | 
| 1794 |     QFETCH(QString, canonicalFilePath); | 
| 1795 |  | 
| 1796 |     QString errorMessage; | 
| 1797 |     DWORD creationResult = ERROR_SUCCESS; | 
| 1798 |     switch (resource.type) { | 
| 1799 |     case NtfsTestResource::None: | 
| 1800 |         break; | 
| 1801 |     case NtfsTestResource::SymLink: | 
| 1802 |         creationResult = createSymbolicLink(resource.source, resource.target, &errorMessage); | 
| 1803 |         break; | 
| 1804 |     case NtfsTestResource::Junction: | 
| 1805 |         creationResult = FileSystem::createNtfsJunction(resource.target, resource.source, &errorMessage); | 
| 1806 |         if (creationResult == ERROR_NOT_SUPPORTED) // Special value indicating non-NTFS drive | 
| 1807 |             QSKIP(qPrintable(errorMessage)); | 
| 1808 |         break; | 
| 1809 |     } | 
| 1810 |  | 
| 1811 |     if (creationResult == ERROR_PRIVILEGE_NOT_HELD) | 
| 1812 |         QSKIP(msgInsufficientPrivileges(errorMessage)); | 
| 1813 |     QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage)); | 
| 1814 |  | 
| 1815 |     QFileInfo fi(path); | 
| 1816 |     auto guard = qScopeGuard([&fi, this]() { | 
| 1817 |         // Ensure that junctions, mountpoints are removed. If this fails, do not remove | 
| 1818 |         // temporary directory to prevent it from trashing the system. | 
| 1819 |         if (fi.isDir()) { | 
| 1820 |             if (!QDir().rmdir(fi.filePath())) { | 
| 1821 |                 qWarning("Unable to remove NTFS junction '%ls', keeping '%ls'." , | 
| 1822 |                          qUtf16Printable(fi.fileName()), | 
| 1823 |                          qUtf16Printable(QDir::toNativeSeparators(m_dir.path()))); | 
| 1824 |                 m_dir.setAutoRemove(false); | 
| 1825 |             } | 
| 1826 |         } | 
| 1827 |     }); | 
| 1828 |     const QString actualSymLinkTarget = isSymLink ? fi.symLinkTarget() : QString(); | 
| 1829 |     const QString actualCanonicalFilePath = isSymLink ? fi.canonicalFilePath() : QString(); | 
| 1830 |     QCOMPARE(fi.isJunction(), resource.type == NtfsTestResource::Junction); | 
| 1831 |     QCOMPARE(fi.isSymbolicLink(), isSymLink); | 
| 1832 |     if (isSymLink) { | 
| 1833 |         QCOMPARE(actualSymLinkTarget, linkTarget); | 
| 1834 |         QCOMPARE(actualCanonicalFilePath, canonicalFilePath); | 
| 1835 |     } | 
| 1836 | } | 
| 1837 |  | 
| 1838 | void tst_QFileInfo::brokenShortcut() | 
| 1839 | { | 
| 1840 |     QString linkName("borkenlink.lnk" ); | 
| 1841 |     QFile::remove(linkName); | 
| 1842 |     QFile file(linkName); | 
| 1843 |     file.open(QFile::WriteOnly); | 
| 1844 |     file.write("b0rk" ); | 
| 1845 |     file.close(); | 
| 1846 |  | 
| 1847 |     QFileInfo info(linkName); | 
| 1848 |     QVERIFY(!info.isSymbolicLink()); | 
| 1849 |     QVERIFY(info.isShortcut()); | 
| 1850 |     QVERIFY(!info.exists()); | 
| 1851 |     QFile::remove(linkName); | 
| 1852 |  | 
| 1853 |     QDir current; // QTBUG-21863 | 
| 1854 |     QVERIFY(current.mkdir(linkName)); | 
| 1855 |     QFileInfo dirInfo(linkName); | 
| 1856 |     QVERIFY(!dirInfo.isSymbolicLink()); | 
| 1857 |     QVERIFY(!dirInfo.isShortcut()); | 
| 1858 |     QVERIFY(dirInfo.isDir()); | 
| 1859 |     current.rmdir(linkName); | 
| 1860 | } | 
| 1861 | #endif | 
| 1862 |  | 
| 1863 | void tst_QFileInfo::isWritable() | 
| 1864 | { | 
| 1865 |     QFile tempfile("tempfile.txt" ); | 
| 1866 |     tempfile.open(flags: QIODevice::WriteOnly); | 
| 1867 |     tempfile.write(data: "This file is generated by the QFileInfo autotest." ); | 
| 1868 |     tempfile.close(); | 
| 1869 |  | 
| 1870 |     QVERIFY(QFileInfo("tempfile.txt" ).isWritable()); | 
| 1871 |     tempfile.remove(); | 
| 1872 |  | 
| 1873 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 1874 |     QFileInfo fi("c:\\pagefile.sys" ); | 
| 1875 |     QVERIFY2(fi.exists(), msgDoesNotExist(fi.absoluteFilePath()).constData()); | 
| 1876 |     QVERIFY(!fi.isWritable()); | 
| 1877 | #endif | 
| 1878 |  | 
| 1879 | #if defined (Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 1880 |     QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup); | 
| 1881 |     qt_ntfs_permission_lookup = 1; | 
| 1882 |     QFileInfo fi2(QFile::decodeName(qgetenv("SystemRoot" ) + "/system.ini" )); | 
| 1883 |     QVERIFY(fi2.exists()); | 
| 1884 |     QCOMPARE(fi2.isWritable(), IsUserAdmin()); | 
| 1885 | #endif | 
| 1886 |  | 
| 1887 | #if defined (Q_OS_QNX) // On QNX /etc is usually on a read-only filesystem | 
| 1888 |     QVERIFY(!QFileInfo("/etc/passwd" ).isWritable()); | 
| 1889 | #elif defined (Q_OS_UNIX) && !defined(Q_OS_VXWORKS) // VxWorks does not have users/groups | 
| 1890 |     for (const char *attempt : { "/etc/passwd" , "/etc/machine-id" , "/proc/version"  }) { | 
| 1891 |         if (access(name: attempt, F_OK) == -1) | 
| 1892 |             continue; | 
| 1893 |         QCOMPARE(QFileInfo(attempt).isWritable(), ::access(attempt, W_OK) == 0); | 
| 1894 |     } | 
| 1895 | #endif | 
| 1896 | } | 
| 1897 |  | 
| 1898 | void tst_QFileInfo::isExecutable() | 
| 1899 | { | 
| 1900 |     QString appPath = QCoreApplication::applicationDirPath(); | 
| 1901 | #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) | 
| 1902 |     appPath += "/libtst_qfileinfo.so" ; | 
| 1903 | #else | 
| 1904 |     appPath += "/tst_qfileinfo" ; | 
| 1905 | # if defined(Q_OS_WIN) | 
| 1906 |     appPath += ".exe" ; | 
| 1907 | # endif | 
| 1908 | #endif | 
| 1909 |     QFileInfo fi(appPath); | 
| 1910 |     QCOMPARE(fi.isExecutable(), true); | 
| 1911 |  | 
| 1912 |     QCOMPARE(QFileInfo(m_proFile).isExecutable(), false); | 
| 1913 |  | 
| 1914 | #ifdef Q_OS_UNIX | 
| 1915 |     QFile::remove(fileName: "link.lnk" ); | 
| 1916 |  | 
| 1917 |     // Symlink to executable | 
| 1918 |     QFile appFile(appPath); | 
| 1919 |     QVERIFY(appFile.link("link.lnk" )); | 
| 1920 |     QCOMPARE(QFileInfo("link.lnk" ).isExecutable(), true); | 
| 1921 |     QFile::remove(fileName: "link.lnk" ); | 
| 1922 |  | 
| 1923 |     // Symlink to .pro file | 
| 1924 |     QFile proFile(m_proFile); | 
| 1925 |     QVERIFY(proFile.link("link.lnk" )); | 
| 1926 |     QCOMPARE(QFileInfo("link.lnk" ).isExecutable(), false); | 
| 1927 |     QFile::remove(fileName: "link.lnk" ); | 
| 1928 | #endif | 
| 1929 |  | 
| 1930 | } | 
| 1931 |  | 
| 1932 |  | 
| 1933 | void tst_QFileInfo::testDecomposedUnicodeNames_data() | 
| 1934 | { | 
| 1935 |     QTest::addColumn<QString>(name: "filePath" ); | 
| 1936 |     QTest::addColumn<QString>(name: "fileName" ); | 
| 1937 |     QTest::addColumn<bool>(name: "exists" ); | 
| 1938 |     QString currPath = QDir::currentPath(); | 
| 1939 |     QTest::newRow(dataTag: "latin-only" ) << currPath + "/4.pdf"  << "4.pdf"  << true; | 
| 1940 |     QTest::newRow(dataTag: "one-decomposed uni" ) << currPath + QString::fromUtf8(str: "/4 ä.pdf" ) << QString::fromUtf8(str: "4 ä.pdf" ) << true; | 
| 1941 |     QTest::newRow(dataTag: "many-decomposed uni" ) << currPath + QString::fromUtf8(str: "/4 äääcopy.pdf" ) << QString::fromUtf8(str: "4 äääcopy.pdf" ) << true; | 
| 1942 |     QTest::newRow(dataTag: "no decomposed" ) << currPath + QString::fromUtf8(str: "/4 øøøcopy.pdf" ) << QString::fromUtf8(str: "4 øøøcopy.pdf" ) << true; | 
| 1943 | } | 
| 1944 |  | 
| 1945 | // This is a helper class that ensures that files created during the test | 
| 1946 | // will be removed afterwards, even if the test fails or throws an exception. | 
| 1947 | class NativeFileCreator | 
| 1948 | { | 
| 1949 | public: | 
| 1950 |     NativeFileCreator(const QString &filePath) | 
| 1951 |         : m_filePath(filePath), m_error(0) | 
| 1952 |     { | 
| 1953 | #ifdef Q_OS_UNIX | 
| 1954 |         int fd = open(file: m_filePath.normalized(mode: QString::NormalizationForm_D).toUtf8().constData(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); | 
| 1955 |         if (fd >= 0) | 
| 1956 |             close(fd: fd); | 
| 1957 |         else | 
| 1958 |             m_error = errno; | 
| 1959 | #endif | 
| 1960 |     } | 
| 1961 |     ~NativeFileCreator() | 
| 1962 |     { | 
| 1963 | #ifdef Q_OS_UNIX | 
| 1964 |         if (m_error == 0) | 
| 1965 |             unlink(name: m_filePath.normalized(mode: QString::NormalizationForm_D).toUtf8().constData()); | 
| 1966 | #endif | 
| 1967 |     } | 
| 1968 |     int error() const | 
| 1969 |     { | 
| 1970 |         return m_error; | 
| 1971 |     } | 
| 1972 |  | 
| 1973 | private: | 
| 1974 |     QString m_filePath; | 
| 1975 |     int m_error; | 
| 1976 | }; | 
| 1977 |  | 
| 1978 | void tst_QFileInfo::testDecomposedUnicodeNames() | 
| 1979 | { | 
| 1980 | #ifndef Q_OS_MAC | 
| 1981 |     QSKIP("This is a OS X only test (unless you know more about filesystems, then maybe you should try it ;)" ); | 
| 1982 | #else | 
| 1983 |     QFETCH(QString, filePath); | 
| 1984 |     NativeFileCreator nativeFileCreator(filePath); | 
| 1985 |     int error = nativeFileCreator.error(); | 
| 1986 |     QVERIFY2(error == 0, qPrintable(QString("Couldn't create native file %1: %2" ).arg(filePath).arg(strerror(error)))); | 
| 1987 |  | 
| 1988 |     QFileInfo file(filePath); | 
| 1989 |     QTEST(file.fileName(), "fileName" ); | 
| 1990 |     QTEST(file.exists(), "exists" ); | 
| 1991 | #endif | 
| 1992 | } | 
| 1993 |  | 
| 1994 | void tst_QFileInfo::equalOperator() const | 
| 1995 | { | 
| 1996 |     /* Compare two default constructed values. Yes, to me it seems it should be the opposite too, but | 
| 1997 |      * this is how the code was written. */ | 
| 1998 |     QVERIFY(!(QFileInfo() == QFileInfo())); | 
| 1999 | } | 
| 2000 |  | 
| 2001 |  | 
| 2002 | void tst_QFileInfo::equalOperatorWithDifferentSlashes() const | 
| 2003 | { | 
| 2004 |     const QFileInfo fi1("/usr" ); | 
| 2005 |     const QFileInfo fi2("/usr/" ); | 
| 2006 |  | 
| 2007 |     QCOMPARE(fi1, fi2); | 
| 2008 | } | 
| 2009 |  | 
| 2010 | void tst_QFileInfo::notEqualOperator() const | 
| 2011 | { | 
| 2012 |     /* Compare two default constructed values. Yes, to me it seems it should be the opposite too, but | 
| 2013 |      * this is how the code was written. */ | 
| 2014 |     QVERIFY(QFileInfo() != QFileInfo()); | 
| 2015 | } | 
| 2016 |  | 
| 2017 | void tst_QFileInfo::detachingOperations() | 
| 2018 | { | 
| 2019 |     QFileInfo info1; | 
| 2020 |     QVERIFY(info1.caching()); | 
| 2021 |     info1.setCaching(false); | 
| 2022 |  | 
| 2023 |     { | 
| 2024 |         QFileInfo info2 = info1; | 
| 2025 |  | 
| 2026 |         QVERIFY(!info1.caching()); | 
| 2027 |         QVERIFY(!info2.caching()); | 
| 2028 |  | 
| 2029 |         info2.setCaching(true); | 
| 2030 |         QVERIFY(info2.caching()); | 
| 2031 |  | 
| 2032 |         info1.setFile("foo" ); | 
| 2033 |         QVERIFY(!info1.caching()); | 
| 2034 |     } | 
| 2035 |  | 
| 2036 |     { | 
| 2037 |         QFile file("foo" ); | 
| 2038 |         info1.setFile(file); | 
| 2039 |         QVERIFY(!info1.caching()); | 
| 2040 |     } | 
| 2041 |  | 
| 2042 |     info1.setFile(dir: QDir(), file: "foo" ); | 
| 2043 |     QVERIFY(!info1.caching()); | 
| 2044 |  | 
| 2045 |     { | 
| 2046 |         QFileInfo info3; | 
| 2047 |         QVERIFY(info3.caching()); | 
| 2048 |  | 
| 2049 |         info3 = info1; | 
| 2050 |         QVERIFY(!info3.caching()); | 
| 2051 |     } | 
| 2052 |  | 
| 2053 |     info1.refresh(); | 
| 2054 |     QVERIFY(!info1.caching()); | 
| 2055 |  | 
| 2056 |     QVERIFY(info1.makeAbsolute()); | 
| 2057 |     QVERIFY(!info1.caching()); | 
| 2058 | } | 
| 2059 |  | 
| 2060 | #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) | 
| 2061 | bool IsUserAdmin() | 
| 2062 | { | 
| 2063 |     BOOL b; | 
| 2064 |     SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; | 
| 2065 |     PSID AdministratorsGroup; | 
| 2066 |     b = AllocateAndInitializeSid( | 
| 2067 |                 &NtAuthority, | 
| 2068 |                 2, | 
| 2069 |                 SECURITY_BUILTIN_DOMAIN_RID, | 
| 2070 |                 DOMAIN_ALIAS_RID_ADMINS, | 
| 2071 |                 0, 0, 0, 0, 0, 0, | 
| 2072 |                 &AdministratorsGroup); | 
| 2073 |     if (b) { | 
| 2074 |         if (!CheckTokenMembership( NULL, AdministratorsGroup, &b)) | 
| 2075 |             b = false; | 
| 2076 |         FreeSid(AdministratorsGroup); | 
| 2077 |     } | 
| 2078 |  | 
| 2079 |     return b != FALSE; | 
| 2080 | } | 
| 2081 |  | 
| 2082 | #endif // Q_OS_WIN && !Q_OS_WINRT | 
| 2083 |  | 
| 2084 | #ifndef Q_OS_WINRT | 
| 2085 | void tst_QFileInfo::owner() | 
| 2086 | { | 
| 2087 |     QString userName; | 
| 2088 | #if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) | 
| 2089 |     { | 
| 2090 |         passwd *user = getpwuid(uid: geteuid()); | 
| 2091 |         QVERIFY(user); | 
| 2092 |         char *usernameBuf = user->pw_name; | 
| 2093 |         userName = QString::fromLocal8Bit(str: usernameBuf); | 
| 2094 |     } | 
| 2095 | #endif | 
| 2096 | #if defined(Q_OS_WIN) | 
| 2097 |     wchar_t  usernameBuf[1024]; | 
| 2098 |     DWORD  bufSize = 1024; | 
| 2099 |     if (GetUserNameW(usernameBuf, &bufSize)) { | 
| 2100 |         userName = QString::fromWCharArray(usernameBuf); | 
| 2101 |         if (IsUserAdmin()) { | 
| 2102 |             // Special case : If the user is a member of Administrators group, all files | 
| 2103 |             // created by the current user are owned by the Administrators group. | 
| 2104 |             LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; | 
| 2105 |             DWORD dwLevel = 0; | 
| 2106 |             DWORD dwFlags = LG_INCLUDE_INDIRECT ; | 
| 2107 |             DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; | 
| 2108 |             DWORD dwEntriesRead = 0; | 
| 2109 |             DWORD dwTotalEntries = 0; | 
| 2110 |             NET_API_STATUS nStatus; | 
| 2111 |             nStatus = NetUserGetLocalGroups(0, usernameBuf, dwLevel, dwFlags, (LPBYTE *) &pBuf, | 
| 2112 |                                             dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries); | 
| 2113 |             // Check if the current user is a member of Administrators group | 
| 2114 |             if (nStatus == NERR_Success && pBuf){ | 
| 2115 |                 for (int i = 0; i < (int)dwEntriesRead; i++) { | 
| 2116 |                     QString groupName = QString::fromWCharArray(pBuf[i].lgrui0_name); | 
| 2117 |                     if (!groupName.compare(QLatin1String("Administrators" ))) | 
| 2118 |                         userName = groupName; | 
| 2119 |                 } | 
| 2120 |             } | 
| 2121 |             if (pBuf != NULL) | 
| 2122 |                 NetApiBufferFree(pBuf); | 
| 2123 |         } | 
| 2124 |     } | 
| 2125 |     qt_ntfs_permission_lookup = 1; | 
| 2126 | #endif | 
| 2127 |     if (userName.isEmpty()) | 
| 2128 |         QSKIP("Can't retrieve the user name" ); | 
| 2129 |     QString fileName("ownertest.txt" ); | 
| 2130 |     QVERIFY(!QFile::exists(fileName) || QFile::remove(fileName)); | 
| 2131 |     { | 
| 2132 |         QFile testFile(fileName); | 
| 2133 |         QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); | 
| 2134 |         QByteArray testData("testfile" ); | 
| 2135 |         QVERIFY(testFile.write(testData) != -1); | 
| 2136 |     } | 
| 2137 |     QFileInfo fi(fileName); | 
| 2138 |     QVERIFY2(fi.exists(), msgDoesNotExist(fi.absoluteFilePath()).constData()); | 
| 2139 |     QCOMPARE(fi.owner(), userName); | 
| 2140 |  | 
| 2141 |     QFile::remove(fileName); | 
| 2142 | #if defined(Q_OS_WIN) | 
| 2143 |     qt_ntfs_permission_lookup = 0; | 
| 2144 | #endif | 
| 2145 | } | 
| 2146 | #endif // !Q_OS_WINRT | 
| 2147 |  | 
| 2148 | void tst_QFileInfo::group() | 
| 2149 | { | 
| 2150 |     QString expected; | 
| 2151 | #if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) | 
| 2152 |     struct group *gr; | 
| 2153 |     gid_t gid = getegid(); | 
| 2154 |  | 
| 2155 |     errno = 0; | 
| 2156 |     gr = getgrgid(gid: gid); | 
| 2157 |  | 
| 2158 |     QVERIFY2(gr, qPrintable( | 
| 2159 |         QString("getgrgid returned 0: %1, cannot determine my own group" ) | 
| 2160 |         .arg(QString::fromLocal8Bit(strerror(errno))))); | 
| 2161 |     expected = QString::fromLocal8Bit(str: gr->gr_name); | 
| 2162 | #endif | 
| 2163 |  | 
| 2164 |     QString fileName("ownertest.txt" ); | 
| 2165 |     if (QFile::exists(fileName)) | 
| 2166 |         QFile::remove(fileName); | 
| 2167 |     QFile testFile(fileName); | 
| 2168 |     QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text)); | 
| 2169 |     QByteArray testData("testfile" ); | 
| 2170 |     QVERIFY(testFile.write(testData) != -1); | 
| 2171 |     testFile.close(); | 
| 2172 |     QFileInfo fi(fileName); | 
| 2173 |     QVERIFY2(fi.exists(), msgDoesNotExist(fi.absoluteFilePath()).constData()); | 
| 2174 |  | 
| 2175 |     QCOMPARE(fi.group(), expected); | 
| 2176 | } | 
| 2177 |  | 
| 2178 | static void stateCheck(const QFileInfo &info, const QString &dirname, const QString &filename) | 
| 2179 | { | 
| 2180 |     QCOMPARE(info.size(), qint64(0)); | 
| 2181 |     QVERIFY(!info.exists()); | 
| 2182 |  | 
| 2183 |     QString path; | 
| 2184 |     QString abspath; | 
| 2185 |     if (!dirname.isEmpty()) { | 
| 2186 |         path = "." ; | 
| 2187 |         abspath = dirname + '/' + filename; | 
| 2188 |     } | 
| 2189 |  | 
| 2190 |     QCOMPARE(info.filePath(), filename); | 
| 2191 |     QCOMPARE(info.absoluteFilePath(), abspath); | 
| 2192 |     QCOMPARE(info.canonicalFilePath(), QString()); | 
| 2193 |     QCOMPARE(info.fileName(), filename); | 
| 2194 |     QCOMPARE(info.baseName(), filename); | 
| 2195 |     QCOMPARE(info.completeBaseName(), filename); | 
| 2196 |     QCOMPARE(info.suffix(), QString()); | 
| 2197 |     QCOMPARE(info.bundleName(), QString()); | 
| 2198 |     QCOMPARE(info.completeSuffix(), QString()); | 
| 2199 |  | 
| 2200 |     QVERIFY(info.isRelative()); | 
| 2201 |     QCOMPARE(info.path(), path); | 
| 2202 |     QCOMPARE(info.absolutePath(), dirname); | 
| 2203 |     QCOMPARE(info.dir().path(), "." ); | 
| 2204 |  | 
| 2205 |     // these don't look right | 
| 2206 |     QCOMPARE(info.canonicalPath(), path); | 
| 2207 |     QCOMPARE(info.absoluteDir().path(), dirname.isEmpty() ? "."  : dirname); | 
| 2208 |  | 
| 2209 |     QVERIFY(!info.isReadable()); | 
| 2210 |     QVERIFY(!info.isWritable()); | 
| 2211 |     QVERIFY(!info.isExecutable()); | 
| 2212 |     QVERIFY(!info.isHidden()); | 
| 2213 |     QVERIFY(!info.isFile()); | 
| 2214 |     QVERIFY(!info.isDir()); | 
| 2215 |     QVERIFY(!info.isSymbolicLink()); | 
| 2216 |     QVERIFY(!info.isShortcut()); | 
| 2217 |     QVERIFY(!info.isBundle()); | 
| 2218 |     QVERIFY(!info.isRoot()); | 
| 2219 |     QCOMPARE(info.isNativePath(), !filename.isEmpty()); | 
| 2220 |  | 
| 2221 |     QCOMPARE(info.symLinkTarget(), QString()); | 
| 2222 |     QCOMPARE(info.ownerId(), uint(-2)); | 
| 2223 |     QCOMPARE(info.groupId(), uint(-2)); | 
| 2224 |     QCOMPARE(info.owner(), QString()); | 
| 2225 |     QCOMPARE(info.group(), QString()); | 
| 2226 |  | 
| 2227 |     QCOMPARE(info.permissions(), QFile::Permissions()); | 
| 2228 |  | 
| 2229 | #if QT_DEPRECATED_SINCE(5, 10) | 
| 2230 |     QVERIFY(!info.created().isValid()); | 
| 2231 | #endif | 
| 2232 |     QVERIFY(!info.birthTime().isValid()); | 
| 2233 |     QVERIFY(!info.metadataChangeTime().isValid()); | 
| 2234 |     QVERIFY(!info.lastRead().isValid()); | 
| 2235 |     QVERIFY(!info.lastModified().isValid()); | 
| 2236 | }; | 
| 2237 |  | 
| 2238 | void tst_QFileInfo::invalidState_data() | 
| 2239 | { | 
| 2240 |     QTest::addColumn<int>(name: "mode" ); | 
| 2241 |     QTest::newRow(dataTag: "default" ) << 0; | 
| 2242 |     QTest::newRow(dataTag: "empty" ) << 1; | 
| 2243 |     QTest::newRow(dataTag: "copy-of-default" ) << 2; | 
| 2244 |     QTest::newRow(dataTag: "copy-of-empty" ) << 3; | 
| 2245 | } | 
| 2246 |  | 
| 2247 | void tst_QFileInfo::invalidState() | 
| 2248 | { | 
| 2249 |     // Shouldn't crash or produce warnings | 
| 2250 |     QFETCH(int, mode); | 
| 2251 |     const QFileInfo &info = (mode & 1 ? QFileInfo("" ) : QFileInfo()); | 
| 2252 |  | 
| 2253 |     if (mode & 2) { | 
| 2254 |         QFileInfo copy(info); | 
| 2255 |         stateCheck(info: copy, dirname: QString(), filename: QString()); | 
| 2256 |     } else { | 
| 2257 |         stateCheck(info, dirname: QString(), filename: QString()); | 
| 2258 |     } | 
| 2259 | } | 
| 2260 |  | 
| 2261 | void tst_QFileInfo::nonExistingFile() | 
| 2262 | { | 
| 2263 |     QString dirname = QDir::currentPath(); | 
| 2264 |     QString cdirname = QFileInfo(dirname).canonicalFilePath(); | 
| 2265 |     if (dirname != cdirname) | 
| 2266 |         QDir::setCurrent(cdirname); // chdir() to our canonical path | 
| 2267 |  | 
| 2268 |     QString filename = "non-existing-file-foobar" ; | 
| 2269 |     QFileInfo info(filename); | 
| 2270 |     stateCheck(info, dirname, filename); | 
| 2271 | } | 
| 2272 |  | 
| 2273 |  | 
| 2274 | QTEST_MAIN(tst_QFileInfo) | 
| 2275 | #include "tst_qfileinfo.moc" | 
| 2276 |  |