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)
69QT_BEGIN_NAMESPACE
70extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
71QT_END_NAMESPACE
72# ifndef Q_OS_WINRT
73bool IsUserAdmin();
74# endif
75#endif
76
77inline 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
83inline 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
104static 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
125static QByteArray msgInsufficientPrivileges(const QString &errorMessage)
126{
127 return "Insufficient privileges (" + errorMessage.toLocal8Bit() + ')';
128}
129#endif // Q_OS_WIN && !Q_OS_WINRT
130
131static 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
143static QByteArray msgDoesNotExist(const QString &name)
144{
145 return (QLatin1Char('"') + QDir::toNativeSeparators(pathName: name)
146 + QLatin1String("\" does not exist.")).toLocal8Bit();
147}
148
149static QByteArray msgIsNoDirectory(const QString &name)
150{
151 return (QLatin1Char('"') + QDir::toNativeSeparators(pathName: name)
152 + QLatin1String("\" is not a directory.")).toLocal8Bit();
153}
154
155static QByteArray msgIsNotRoot(const QString &name)
156{
157 return (QLatin1Char('"') + QDir::toNativeSeparators(pathName: name)
158 + QLatin1String("\" is no root directory.")).toLocal8Bit();
159}
160
161class tst_QFileInfo : public QObject
162{
163Q_OBJECT
164
165public:
166 tst_QFileInfo() : m_currentDir(QDir::currentPath()), m_dir(seedAndTemplate())
167 {}
168
169private 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
290private:
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
299void 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
315void 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
321void 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
332static QFileInfoPrivate* getPrivate(QFileInfo &info)
333{
334 return (*reinterpret_cast<QFileInfoPrivate**>(&info));
335}
336
337void 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
373void 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
385void 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
395void 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
439void 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
451void 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
480void 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
492void 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
533void 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
547void 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
586void 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
598void 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
629void 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
642void 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
651class FileDeleter {
652 Q_DISABLE_COPY(FileDeleter)
653public:
654 explicit FileDeleter(const QString fileName) : m_fileName(fileName) {}
655 ~FileDeleter() { QFile::remove(fileName: m_fileName); }
656
657private:
658 const QString m_fileName;
659};
660
661void 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
781void 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
804void tst_QFileInfo::fileName()
805{
806 QFETCH(QString, file);
807 QFETCH(QString, expected);
808
809 QFileInfo fi(file);
810 QCOMPARE(fi.fileName(), expected);
811}
812
813void 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
825void tst_QFileInfo::bundleName()
826{
827 QFETCH(QString, file);
828 QFETCH(QString, expected);
829
830 QFileInfo fi(file);
831 QCOMPARE(fi.bundleName(), expected);
832}
833
834void 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
853void 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
870void 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
898void 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
908void 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
927void tst_QFileInfo::completeSuffix()
928{
929 QFETCH(QString, file);
930 QFETCH(QString, expected);
931
932 QFileInfo fi(file);
933 QCOMPARE(fi.completeSuffix(), expected);
934}
935
936void 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
954void tst_QFileInfo::baseName()
955{
956 QFETCH(QString, file);
957 QFETCH(QString, expected);
958
959 QFileInfo fi(file);
960 QCOMPARE(fi.baseName(), expected);
961}
962
963void 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
981void tst_QFileInfo::completeBaseName()
982{
983 QFETCH(QString, file);
984 QFETCH(QString, expected);
985
986 QFileInfo fi(file);
987 QCOMPARE(fi.completeBaseName(), expected);
988}
989
990void 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
1003void 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
1012void 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
1027void 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
1036void 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
1054void 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
1087void 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
1101void 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
1113void 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
1124void 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
1140void 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
1262void 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
1274void 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
1298void 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
1330void 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
1345void 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
1376void tst_QFileInfo::isShortcut()
1377{
1378 QFETCH(QString, path);
1379 QFETCH(bool, isShortcut);
1380
1381 QFileInfo fi(path);
1382 QCOMPARE(fi.isShortcut(), isShortcut);
1383}
1384
1385void 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
1423void tst_QFileInfo::isSymbolicLink()
1424{
1425 QFETCH(QString, path);
1426 QFETCH(bool, isSymbolicLink);
1427
1428 QFileInfo fi(path);
1429 QCOMPARE(fi.isSymbolicLink(), isSymbolicLink);
1430}
1431
1432void 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
1502void 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
1515void 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
1550void 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)
1560void 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
1580void 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
1591void tst_QFileInfo::isBundle()
1592{
1593 QFETCH(QString, path);
1594 QFETCH(bool, isBundle);
1595 QFileInfo fi(path);
1596 QCOMPARE(fi.isBundle(), isBundle);
1597}
1598
1599void 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
1613void 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
1624void 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
1665struct 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
1677Q_DECLARE_METATYPE(NtfsTestResource)
1678
1679void 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
1788void 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
1838void 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
1863void 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
1898void 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
1933void 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.
1947class NativeFileCreator
1948{
1949public:
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
1973private:
1974 QString m_filePath;
1975 int m_error;
1976};
1977
1978void 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
1994void 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
2002void tst_QFileInfo::equalOperatorWithDifferentSlashes() const
2003{
2004 const QFileInfo fi1("/usr");
2005 const QFileInfo fi2("/usr/");
2006
2007 QCOMPARE(fi1, fi2);
2008}
2009
2010void 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
2017void 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)
2061bool 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
2085void 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
2148void 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
2178static 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
2238void 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
2247void 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
2261void 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
2274QTEST_MAIN(tst_QFileInfo)
2275#include "tst_qfileinfo.moc"
2276

source code of qtbase/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp