1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 
43 #include <QtTest/QtTest>
44 
45 
46 #include <qfile.h>
47 #include <qdir.h>
48 #include <qcoreapplication.h>
49 #include <qlibrary.h>
50 #include <qtemporaryfile.h>
51 #include <qdir.h>
52 #include <qfileinfo.h>
53 #ifdef Q_OS_UNIX
54 #include <fcntl.h>
55 #include <unistd.h>
56 #include <sys/stat.h>
57 #include <sys/types.h>
58 #include <pwd.h>
59 #endif
60 #ifdef Q_OS_WIN
61 #define _WIN32_WINNT  0x500
62 #include <qt_windows.h>
63 #include <qlibrary.h>
64 #ifndef Q_OS_WINCE
65 #include <lm.h>
66 #endif
67 #endif
68 #include <qplatformdefs.h>
69 #include <qdebug.h>
70 #ifdef Q_OS_SYMBIAN
71 #include <f32file.h>
72 #include <private/qcore_symbian_p.h>
73 #endif
74 #include "../network-settings.h"
75 #include <private/qfileinfo_p.h>
76 #include "../../shared/filesystem.h"
77 
78 #if defined(Q_OS_SYMBIAN)
79 # define NO_SYMLINKS
80 #endif
81 
82 QT_BEGIN_NAMESPACE
83 extern Q_AUTOTEST_EXPORT bool qIsLikelyToBeNfs(int /* handle */);
84 QT_END_NAMESPACE
85 
86 //TESTED_CLASS=
87 //TESTED_FILES=
88 
89 class tst_QFileInfo : public QObject
90 {
91 Q_OBJECT
92 
93 public:
94     tst_QFileInfo();
95     ~tst_QFileInfo();
96 
97 private slots:
98     void getSetCheck();
99 
100     void copy();
101 
102     void isFile_data();
103     void isFile();
104 
105     void isDir_data();
106     void isDir();
107 
108     void isRoot_data();
109     void isRoot();
110 
111     void exists_data();
112     void exists();
113 
114     void absolutePath_data();
115     void absolutePath();
116 
117     void absFilePath_data();
118     void absFilePath();
119 
120     void canonicalPath();
121     void canonicalFilePath();
122 
123     void fileName_data();
124     void fileName();
125 
126     void bundleName_data();
127     void bundleName();
128 
129     void dir_data();
130     void dir();
131 
132     void suffix_data();
133     void suffix();
134 
135     void completeSuffix_data();
136     void completeSuffix();
137 
138     void baseName_data();
139     void baseName();
140 
141     void completeBaseName_data();
142     void completeBaseName();
143 
144     void permission_data();
145     void permission();
146 
147     void size_data();
148     void size();
149 
150     void systemFiles();
151 
152     void compare_data();
153     void compare();
154 
155     void consistent_data();
156     void consistent();
157 
158     void fileTimes_data();
159     void fileTimes();
160     void fileTimes_oldFile();
161 
162     void isSymLink_data();
163     void isSymLink();
164 
165     void isHidden_data();
166     void isHidden();
167 #if defined(Q_OS_MAC)
168     void isHiddenFromFinder();
169 #endif
170 
171     void isBundle_data();
172     void isBundle();
173 
174     void isLocalFs_data();
175     void isLocalFs();
176 
177     void refresh();
178 
179 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
180     void ntfsJunctionPointsAndSymlinks_data();
181     void ntfsJunctionPointsAndSymlinks();
182     void brokenShortcut();
183 #endif
184 
185     void isWritable();
186     void isExecutable();
187     void testDecomposedUnicodeNames_data();
188     void testDecomposedUnicodeNames();
189 
190     void equalOperator() const;
191     void equalOperatorWithDifferentSlashes() const;
192     void notEqualOperator() const;
193 
194     void detachingOperations();
195 
196 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
197     void owner();
198 #endif
199     void group();
200 
201     void invalidState();
202 };
203 
tst_QFileInfo()204 tst_QFileInfo::tst_QFileInfo()
205 {
206 }
207 
~tst_QFileInfo()208 tst_QFileInfo::~tst_QFileInfo()
209 {
210     QFile::remove("brokenlink.lnk");
211     QFile::remove("link.lnk");
212     QFile::remove("file1");
213     QFile::remove("dummyfile");
214     QFile::remove("simplefile.txt");
215     QFile::remove("longFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileNamelongFileName.txt");
216 #ifdef Q_OS_SYMBIAN
217     QFile::remove("hidden.txt");
218     QFile::remove("nothidden.txt");
219 #else
220     QFile::remove("tempfile.txt");
221 #endif
222 
223 #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
224     QDir().rmdir("./.hidden-directory");
225     QFile::remove("link_to_tst_qfileinfo");
226 #endif
227 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
228     QDir().rmdir("./hidden-directory");
229     QDir().rmdir("abs_symlink");
230     QDir().rmdir("rel_symlink");
231     QDir().rmdir("junction_pwd");
232     QDir().rmdir("junction_root");
233     QDir().rmdir("mountpoint");
234     QFile::remove("abs_symlink.cpp");
235     QFile::remove("rel_symlink.cpp");
236 #endif
237 }
238 
239 // Testing get/set functions
getSetCheck()240 void tst_QFileInfo::getSetCheck()
241 {
242     QFileInfo obj1;
243     // bool QFileInfo::caching()
244     // void QFileInfo::setCaching(bool)
245     obj1.setCaching(false);
246     QCOMPARE(false, obj1.caching());
247     obj1.setCaching(true);
248     QCOMPARE(true, obj1.caching());
249 }
250 
getPrivate(QFileInfo & info)251 static QFileInfoPrivate* getPrivate(QFileInfo &info)
252 {
253     return (*reinterpret_cast<QFileInfoPrivate**>(&info));
254 }
255 
copy()256 void tst_QFileInfo::copy()
257 {
258     QTemporaryFile t;
259     t.open();
260     QFileInfo info(t.fileName());
261     QVERIFY(info.exists());
262 
263     //copy constructor
264     QFileInfo info2(info);
265     QFileInfoPrivate *privateInfo = getPrivate(info);
266     QFileInfoPrivate *privateInfo2 = getPrivate(info2);
267     QCOMPARE(privateInfo, privateInfo2);
268 
269     //operator =
270     QFileInfo info3 = info;
271     QFileInfoPrivate *privateInfo3 = getPrivate(info3);
272     QCOMPARE(privateInfo, privateInfo3);
273     QCOMPARE(privateInfo2, privateInfo3);
274 
275     //refreshing info3 will detach it
276     QFile file(info.absoluteFilePath());
277     QVERIFY(file.open(QFile::WriteOnly));
278     QCOMPARE(file.write("JAJAJAA"), qint64(7));
279     file.flush();
280 
281     QTest::qWait(250);
282 #if defined(Q_OS_WIN) || defined(Q_OS_WINCE)
283     if (QSysInfo::windowsVersion() & QSysInfo::WV_VISTA ||
284                 QSysInfo::windowsVersion() & QSysInfo::WV_CE_based)
285         file.close();
286 #endif
287 #if defined(Q_OS_WINCE)
288     // On Windows CE we need to close the file.
289     // Otherwise the content will be cached and not
290     // flushed to the storage, although we flushed it
291     // manually!!! CE has interim cache, we cannot influence.
292     QTest::qWait(5000);
293 #endif
294     info3.refresh();
295     privateInfo3 = getPrivate(info3);
296     QVERIFY(privateInfo != privateInfo3);
297     QVERIFY(privateInfo2 != privateInfo3);
298     QCOMPARE(privateInfo, privateInfo2);
299 }
300 
isFile_data()301 void tst_QFileInfo::isFile_data()
302 {
303     QTest::addColumn<QString>("path");
304     QTest::addColumn<bool>("expected");
305 
306     QTest::newRow("data0") << QDir::currentPath() << false;
307     QTest::newRow("data1") << SRCDIR "tst_qfileinfo.cpp" << true;
308     QTest::newRow("data2") << ":/tst_qfileinfo/resources/" << false;
309     QTest::newRow("data3") << ":/tst_qfileinfo/resources/file1" << true;
310     QTest::newRow("data4") << ":/tst_qfileinfo/resources/afilethatshouldnotexist" << false;
311 }
312 
isFile()313 void tst_QFileInfo::isFile()
314 {
315     QFETCH(QString, path);
316     QFETCH(bool, expected);
317 
318     QFileInfo fi(path);
319     QCOMPARE(fi.isFile(), expected);
320 }
321 
322 
isDir_data()323 void tst_QFileInfo::isDir_data()
324 {
325     // create a broken symlink
326     QFile::remove("brokenlink.lnk");
327     QFile::remove("dummyfile");
328     QFile file3("dummyfile");
329     file3.open(QIODevice::WriteOnly);
330     if (file3.link("brokenlink.lnk")) {
331         file3.remove();
332         QFileInfo info3("brokenlink.lnk");
333         QVERIFY( info3.isSymLink() );
334     }
335 
336     QTest::addColumn<QString>("path");
337     QTest::addColumn<bool>("expected");
338 
339     QTest::newRow("data0") << QDir::currentPath() << true;
340     QTest::newRow("data1") << SRCDIR "tst_qfileinfo.cpp" << false;
341     QTest::newRow("data2") << ":/tst_qfileinfo/resources/" << true;
342     QTest::newRow("data3") << ":/tst_qfileinfo/resources/file1" << false;
343     QTest::newRow("data4") << ":/tst_qfileinfo/resources/afilethatshouldnotexist" << false;
344 
345     QTest::newRow("simple dir") << SRCDIR "resources" << true;
346     QTest::newRow("simple dir with slash") << SRCDIR "resources/" << true;
347 
348     QTest::newRow("broken link") << "brokenlink.lnk" << false;
349 
350 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
351     QTest::newRow("drive 1") << "c:" << true;
352     QTest::newRow("drive 2") << "c:/" << true;
353     //QTest::newRow("drive 2") << "t:s" << false;
354 #endif
355 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
356     QTest::newRow("unc 1") << "//"  + QtNetworkSettings::winServerName() << true;
357     QTest::newRow("unc 2") << "//"  + QtNetworkSettings::winServerName() + "/" << true;
358     QTest::newRow("unc 3") << "//"  + QtNetworkSettings::winServerName() + "/testshare" << true;
359     QTest::newRow("unc 4") << "//"  + QtNetworkSettings::winServerName() + "/testshare/" << true;
360     QTest::newRow("unc 5") << "//"  + QtNetworkSettings::winServerName() + "/testshare/tmp" << true;
361     QTest::newRow("unc 6") << "//"  + QtNetworkSettings::winServerName() + "/testshare/tmp/" << true;
362     QTest::newRow("unc 7") << "//"  + QtNetworkSettings::winServerName() + "/testshare/adirthatshouldnotexist" << false;
363 #endif
364 }
365 
isDir()366 void tst_QFileInfo::isDir()
367 {
368     QFETCH(QString, path);
369     QFETCH(bool, expected);
370 
371     QFileInfo fi(path);
372     QCOMPARE(fi.isDir(), expected);
373 }
374 
isRoot_data()375 void tst_QFileInfo::isRoot_data()
376 {
377     QTest::addColumn<QString>("path");
378     QTest::addColumn<bool>("expected");
379     QTest::newRow("data0") << QDir::currentPath() << false;
380     QTest::newRow("data1") << "/" << true;
381     QTest::newRow("data2") << "*" << false;
382     QTest::newRow("data3") << "/*" << false;
383     QTest::newRow("data4") << ":/tst_qfileinfo/resources/" << false;
384     QTest::newRow("data5") << ":/" << true;
385 
386     QTest::newRow("simple dir") << SRCDIR "resources" << false;
387     QTest::newRow("simple dir with slash") << SRCDIR "resources/" << false;
388 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
389     QTest::newRow("drive 1") << "c:" << false;
390     QTest::newRow("drive 2") << "c:/" << true;
391     QTest::newRow("drive 3") << "p:/" << false;
392 #endif
393 
394 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
395     QTest::newRow("unc 1") << "//"  + QtNetworkSettings::winServerName() << true;
396     QTest::newRow("unc 2") << "//"  + QtNetworkSettings::winServerName() + "/" << true;
397     QTest::newRow("unc 3") << "//"  + QtNetworkSettings::winServerName() + "/testshare" << false;
398     QTest::newRow("unc 4") << "//"  + QtNetworkSettings::winServerName() + "/testshare/" << false;
399     QTest::newRow("unc 7") << "//ahostthatshouldnotexist" << false;
400 #endif
401 }
402 
isRoot()403 void tst_QFileInfo::isRoot()
404 {
405     QFETCH(QString, path);
406     QFETCH(bool, expected);
407 
408     QFileInfo fi(path);
409     QCOMPARE(fi.isRoot(), expected);
410 }
411 
exists_data()412 void tst_QFileInfo::exists_data()
413 {
414     QTest::addColumn<QString>("path");
415     QTest::addColumn<bool>("expected");
416 
417     QTest::newRow("data0") << QDir::currentPath() << true;
418     QTest::newRow("data1") << SRCDIR "tst_qfileinfo.cpp" << true;
419     QTest::newRow("data2") << "/I/do_not_expect_this_path_to_exist/" << false;
420     QTest::newRow("data3") << ":/tst_qfileinfo/resources/" << true;
421     QTest::newRow("data4") << ":/tst_qfileinfo/resources/file1" << true;
422     QTest::newRow("data5") << ":/I/do_not_expect_this_path_to_exist/" << false;
423     QTest::newRow("data6") << SRCDIR "resources/*" << false;
424     QTest::newRow("data7") << SRCDIR "resources/*.foo" << false;
425     QTest::newRow("data8") << SRCDIR "resources/*.ext1" << false;
426     QTest::newRow("data9") << SRCDIR "resources/file?.ext1" << false;
427     QTest::newRow("data10") << "." << true;
428     QTest::newRow("data11") << ". " << false;
429     QTest::newRow("empty") << "" << false;
430 
431     QTest::newRow("simple dir") << SRCDIR "resources" << true;
432     QTest::newRow("simple dir with slash") << SRCDIR "resources/" << true;
433 
434 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
435     QTest::newRow("unc 1") << "//"  + QtNetworkSettings::winServerName() << true;
436     QTest::newRow("unc 2") << "//"  + QtNetworkSettings::winServerName() + "/" << true;
437     QTest::newRow("unc 3") << "//"  + QtNetworkSettings::winServerName() + "/testshare" << true;
438     QTest::newRow("unc 4") << "//"  + QtNetworkSettings::winServerName() + "/testshare/" << true;
439     QTest::newRow("unc 5") << "//"  + QtNetworkSettings::winServerName() + "/testshare/tmp" << true;
440     QTest::newRow("unc 6") << "//"  + QtNetworkSettings::winServerName() + "/testshare/tmp/" << true;
441     QTest::newRow("unc 7") << "//"  + QtNetworkSettings::winServerName() + "/testshare/adirthatshouldnotexist" << false;
442     QTest::newRow("unc 8") << "//"  + QtNetworkSettings::winServerName() + "/asharethatshouldnotexist" << false;
443     QTest::newRow("unc 9") << "//ahostthatshouldnotexist" << false;
444 #endif
445 }
446 
exists()447 void tst_QFileInfo::exists()
448 {
449     QFETCH(QString, path);
450     QFETCH(bool, expected);
451 
452     QFileInfo fi(path);
453     QCOMPARE(fi.exists(), expected);
454 }
455 
absolutePath_data()456 void tst_QFileInfo::absolutePath_data()
457 {
458     QTest::addColumn<QString>("file");
459     QTest::addColumn<QString>("path");
460     QTest::addColumn<QString>("filename");
461 
462     QString drivePrefix;
463 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
464     drivePrefix = QDir::currentPath().left(2);
465     QString nonCurrentDrivePrefix =
466         drivePrefix.left(1).compare("X", Qt::CaseInsensitive) == 0 ? QString("Y:") : QString("X:");
467 
468     // Make sure drive-relative paths return correct absolute paths (task 255326)
469     QTest::newRow("<current drive>:my.dll") << drivePrefix + "my.dll" << QDir::currentPath() << "my.dll";
470     QTest::newRow("<not current drive>:my.dll") << nonCurrentDrivePrefix + "my.dll"
471                                                 << nonCurrentDrivePrefix + "/"
472                                                 << "my.dll";
473 #endif
474     QTest::newRow("0") << "/machine/share/dir1/" << drivePrefix + "/machine/share/dir1" << "";
475     QTest::newRow("1") << "/machine/share/dir1" << drivePrefix + "/machine/share" << "dir1";
476     QTest::newRow("2") << "/usr/local/bin" << drivePrefix + "/usr/local" << "bin";
477     QTest::newRow("3") << "/usr/local/bin/" << drivePrefix + "/usr/local/bin" << "";
478     QTest::newRow("/test") << "/test" << drivePrefix + "/" << "test";
479 
480 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
481     // see task 102898
482     QTest::newRow("c:\\autoexec.bat") << "c:\\autoexec.bat" << "C:/"
483                                       << "autoexec.bat";
484     QTest::newRow("c:autoexec.bat") << QDir::currentPath().left(2) + "autoexec.bat" << QDir::currentPath()
485                                     << "autoexec.bat";
486 #endif
487     QTest::newRow("QTBUG-19995.1") << drivePrefix + "/System/Library/StartupItems/../Frameworks"
488                                    << drivePrefix + "/System/Library"
489                                    << "Frameworks";
490     QTest::newRow("QTBUG-19995.2") << drivePrefix + "/System/Library/StartupItems/../Frameworks/"
491                                    << drivePrefix + "/System/Library/Frameworks" << "";
492 }
493 
absolutePath()494 void tst_QFileInfo::absolutePath()
495 {
496     QFETCH(QString, file);
497     QFETCH(QString, path);
498     QFETCH(QString, filename);
499 
500     QFileInfo fi(file);
501 
502     QCOMPARE(fi.absolutePath(), path);
503     QCOMPARE(fi.fileName(), filename);
504 }
505 
absFilePath_data()506 void tst_QFileInfo::absFilePath_data()
507 {
508     QTest::addColumn<QString>("file");
509     QTest::addColumn<QString>("expected");
510 
511     QTest::newRow("relativeFile") << "tmp.txt" << QDir::currentPath() + "/tmp.txt";
512     QTest::newRow("relativeFileInSubDir") << "temp/tmp.txt" << QDir::currentPath() + "/" + "temp/tmp.txt";
513     QString drivePrefix;
514 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
515     QString curr = QDir::currentPath();
516 
517     curr.remove(0, 2);   // Make it a absolute path with no drive specifier: \depot\qt-4.2\tests\auto\qfileinfo
518     QTest::newRow(".")            << curr << QDir::currentPath();
519     QTest::newRow("absFilePath") << "c:\\home\\andy\\tmp.txt" << "C:/home/andy/tmp.txt";
520 
521     // Make sure drive-relative paths return correct absolute paths (task 255326)
522     drivePrefix = QDir::currentPath().left(2);
523     QString nonCurrentDrivePrefix =
524         drivePrefix.left(1).compare("X", Qt::CaseInsensitive) == 0 ? QString("Y:") : QString("X:");
525 
526     QTest::newRow("absFilePathWithoutSlash") << drivePrefix + "tmp.txt" << QDir::currentPath() + "/tmp.txt";
527     QTest::newRow("<current drive>:my.dll") << drivePrefix + "temp/my.dll" << QDir::currentPath() + "/temp/my.dll";
528     QTest::newRow("<not current drive>:my.dll") << nonCurrentDrivePrefix + "temp/my.dll"
529                                                 << nonCurrentDrivePrefix + "/temp/my.dll";
530 #else
531     QTest::newRow("absFilePath") << "/home/andy/tmp.txt" << "/home/andy/tmp.txt";
532 #endif
533     QTest::newRow("QTBUG-19995") << drivePrefix + "/System/Library/StartupItems/../Frameworks"
534                                  << drivePrefix + "/System/Library/Frameworks";
535 }
536 
absFilePath()537 void tst_QFileInfo::absFilePath()
538 {
539     QFETCH(QString, file);
540     QFETCH(QString, expected);
541 
542     QFileInfo fi(file);
543 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
544     QVERIFY(QString::compare(fi.absoluteFilePath(), expected, Qt::CaseInsensitive) == 0);
545 #else
546     QCOMPARE(fi.absoluteFilePath(), expected);
547 #endif
548 }
549 
canonicalPath()550 void tst_QFileInfo::canonicalPath()
551 {
552     QTemporaryFile tempFile;
553     tempFile.setAutoRemove(true);
554     tempFile.open();
555     QFileInfo fi(tempFile.fileName());
556     QCOMPARE(fi.canonicalPath(), QFileInfo(QDir::tempPath()).canonicalFilePath());
557 }
558 
canonicalFilePath()559 void tst_QFileInfo::canonicalFilePath()
560 {
561     const QString fileName("tmp.canon");
562     QFile tempFile(fileName);
563     QVERIFY(tempFile.open(QFile::WriteOnly));
564     QFileInfo fi(tempFile.fileName());
565     QCOMPARE(fi.canonicalFilePath(), QDir::currentPath() + "/" + fileName);
566     tempFile.remove();
567 
568     // This used to crash on Mac, verify that it doesn't anymore.
569     QFileInfo info("/tmp/../../../../../../../../../../../../../../../../../");
570     info.canonicalFilePath();
571 
572 #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
573     // This used to crash on Mac
574     QFileInfo dontCrash(QLatin1String("/"));
575     QCOMPARE(dontCrash.canonicalFilePath(), QLatin1String("/"));
576 #endif
577 
578 #ifndef Q_OS_WIN
579     // test symlinks
580     QFile::remove("link.lnk");
581     {
582         QFile file(SRCDIR "tst_qfileinfo.cpp");
583         if (file.link("link.lnk")) {
584             QFileInfo info1(file);
585             QFileInfo info2("link.lnk");
586             QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath());
587         }
588     }
589 #  if !defined(Q_OS_SYMBIAN)
590     // Symbian doesn't support links to directories
591     {
592         const QString link(QDir::tempPath() + QDir::separator() + "tst_qfileinfo");
593         QFile::remove(link);
594         QFile file(QDir::currentPath());
595         if (file.link(link)) {
596             QFile tempfile("tempfile.txt");
597             tempfile.open(QIODevice::ReadWrite);
598             tempfile.write("This file is generated by the QFileInfo autotest.");
599             QVERIFY(tempfile.flush());
600             tempfile.close();
601 
602             QFileInfo info1("tempfile.txt");
603             QFileInfo info2(link + QDir::separator() + "tempfile.txt");
604 
605             QVERIFY(info1.exists());
606             QVERIFY(info2.exists());
607             QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath());
608 
609             QFileInfo info3(link + QDir::separator() + "link.lnk");
610             QFileInfo info4(SRCDIR "tst_qfileinfo.cpp");
611             QVERIFY(!info3.canonicalFilePath().isEmpty());
612             QCOMPARE(info4.canonicalFilePath(), info3.canonicalFilePath());
613 
614             tempfile.remove();
615         }
616     }
617     {
618         QString link(QDir::tempPath() + QDir::separator() + "tst_qfileinfo"
619                      + QDir::separator() + "link_to_tst_qfileinfo");
620         QFile::remove(link);
621 
622         QFile file(QDir::tempPath() + QDir::separator() + "tst_qfileinfo"
623                    + QDir::separator() + "tst_qfileinfo.cpp");
624         if (file.link(link))
625         {
626             QFileInfo info1("tst_qfileinfo.cpp");
627             QFileInfo info2(link);
628             QCOMPARE(info1.canonicalFilePath(), info2.canonicalFilePath());
629         }
630     }
631 #  endif
632 #endif
633 
634 #ifdef Q_OS_WIN
635     typedef BOOL (WINAPI *PtrCreateSymbolicLink)(LPTSTR, LPTSTR, DWORD);
636     PtrCreateSymbolicLink ptrCreateSymbolicLink =
637             (PtrCreateSymbolicLink)QLibrary::resolve(QLatin1String("kernel32"), "CreateSymbolicLinkW");
638 
639     if (!ptrCreateSymbolicLink) {
640         QSKIP("Symbolic links aren't supported by FS", SkipAll);
641     } else {
642         // CreateSymbolicLink can return TRUE & still fail to create the link,
643         // the error code in that case is ERROR_PRIVILEGE_NOT_HELD (1314)
644         SetLastError(0);
645         BOOL ret = ptrCreateSymbolicLink((wchar_t*)QString("res").utf16(), (wchar_t*)QString("resources").utf16(), 1);
646         DWORD dwErr = GetLastError();
647         if (!ret)
648             QSKIP("Symbolic links aren't supported by FS", SkipAll);
649         QString currentPath = QDir::currentPath();
650         bool is_res_Current = QDir::setCurrent("res");
651         if (!is_res_Current && dwErr == 1314)
652             QSKIP("Not enough privilages to create Symbolic links", SkipAll);
653         QCOMPARE(is_res_Current, true);
654 
655         QCOMPARE(QFileInfo("file1").canonicalFilePath(), currentPath + "/resources/file1");
656 
657         QCOMPARE(QDir::setCurrent(currentPath), true);
658         QDir::current().rmdir("res");
659     }
660 #endif
661 }
662 
fileName_data()663 void tst_QFileInfo::fileName_data()
664 {
665     QTest::addColumn<QString>("file");
666     QTest::addColumn<QString>("expected");
667 
668     QTest::newRow("relativeFile") << "tmp.txt" << "tmp.txt";
669     QTest::newRow("relativeFileInSubDir") << "temp/tmp.txt" << "tmp.txt";
670 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
671     QTest::newRow("absFilePath") << "c:\\home\\andy\\tmp.txt" << "tmp.txt";
672     QTest::newRow("driveWithNoSlash") << "c:tmp.txt" << "tmp.txt";
673 #else
674     QTest::newRow("absFilePath") << "/home/andy/tmp.txt" << "tmp.txt";
675 #endif
676     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "file1.ext1";
677     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "file1.ext1.ext2";
678 
679     QTest::newRow("ending slash [small]") << QString::fromLatin1("/a/") << QString::fromLatin1("");
680     QTest::newRow("no ending slash [small]") << QString::fromLatin1("/a") << QString::fromLatin1("a");
681 
682     QTest::newRow("ending slash") << QString::fromLatin1("/somedir/") << QString::fromLatin1("");
683     QTest::newRow("no ending slash") << QString::fromLatin1("/somedir") << QString::fromLatin1("somedir");
684 }
685 
fileName()686 void tst_QFileInfo::fileName()
687 {
688     QFETCH(QString, file);
689     QFETCH(QString, expected);
690 
691     QFileInfo fi(file);
692     QCOMPARE(fi.fileName(), expected);
693 }
694 
bundleName_data()695 void tst_QFileInfo::bundleName_data()
696 {
697     QTest::addColumn<QString>("file");
698     QTest::addColumn<QString>("expected");
699 
700     QTest::newRow("root") << "/" << "";
701     QTest::newRow("etc") << "/etc" << "";
702 #ifdef Q_OS_MAC
703     QTest::newRow("safari") << "/Applications/Safari.app" << "Safari";
704 #endif
705 }
706 
bundleName()707 void tst_QFileInfo::bundleName()
708 {
709     QFETCH(QString, file);
710     QFETCH(QString, expected);
711 
712     QFileInfo fi(file);
713     QCOMPARE(fi.bundleName(), expected);
714 }
715 
dir_data()716 void tst_QFileInfo::dir_data()
717 {
718     QTest::addColumn<QString>("file");
719     QTest::addColumn<bool>("absPath");
720     QTest::addColumn<QString>("expected");
721 
722     QTest::newRow("relativeFile") << "tmp.txt" << false << ".";
723     QTest::newRow("relativeFileAbsPath") << "tmp.txt" << true << QDir::currentPath();
724     QTest::newRow("relativeFileInSubDir") << "temp/tmp.txt" << false << "temp";
725     QTest::newRow("relativeFileInSubDirAbsPath") << "temp/tmp.txt" << true << QDir::currentPath() + "/temp";
726     QTest::newRow("absFilePath") << QDir::currentPath() + "/tmp.txt" << false << QDir::currentPath();
727     QTest::newRow("absFilePathAbsPath") << QDir::currentPath() + "/tmp.txt" << true << QDir::currentPath();
728     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << true << ":/tst_qfileinfo/resources";
729 #ifdef Q_OS_WIN
730     QTest::newRow("driveWithSlash") << "C:/file1.ext1.ext2" << true << "C:/";
731     QTest::newRow("driveWithoutSlash") << QDir::currentPath().left(2) + "file1.ext1.ext2" << false << QDir::currentPath().left(2);
732 #endif
733 }
734 
dir()735 void tst_QFileInfo::dir()
736 {
737     QFETCH(QString, file);
738     QFETCH(bool, absPath);
739     QFETCH(QString, expected);
740 
741     QFileInfo fi(file);
742     if (absPath) {
743         QCOMPARE(fi.absolutePath(), expected);
744         QCOMPARE(fi.absoluteDir().path(), expected);
745 #ifdef QT3_SUPPORT
746         QCOMPARE(fi.dir(true).path(), expected);
747 #endif
748     } else {
749         QCOMPARE(fi.path(), expected);
750         QCOMPARE(fi.dir().path(), expected);
751 #ifdef QT3_SUPPORT
752         QCOMPARE(fi.dir(false).path(), expected);
753 #endif
754     }
755 }
756 
757 
suffix_data()758 void tst_QFileInfo::suffix_data()
759 {
760     QTest::addColumn<QString>("file");
761     QTest::addColumn<QString>("expected");
762 
763     QTest::newRow("noextension0") << "file" << "";
764     QTest::newRow("noextension1") << "/path/to/file" << "";
765     QTest::newRow("data0") << "file.tar" << "tar";
766     QTest::newRow("data1") << "file.tar.gz" << "gz";
767     QTest::newRow("data2") << "/path/file/file.tar.gz" << "gz";
768     QTest::newRow("data3") << "/path/file.tar" << "tar";
769     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "ext1";
770     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "ext2";
771     QTest::newRow("hidden1") << ".ext1" << "ext1";
772     QTest::newRow("hidden1") << ".ext" << "ext";
773     QTest::newRow("hidden1") << ".ex" << "ex";
774     QTest::newRow("hidden1") << ".e" << "e";
775     QTest::newRow("hidden2") << ".ext1.ext2" << "ext2";
776     QTest::newRow("hidden2") << ".ext.ext2" << "ext2";
777     QTest::newRow("hidden2") << ".ex.ext2" << "ext2";
778     QTest::newRow("hidden2") << ".e.ext2" << "ext2";
779     QTest::newRow("hidden2") << "..ext2" << "ext2";
780 #ifdef Q_OS_WIN
781     QTest::newRow("driveWithSlash") << "c:/file1.ext1.ext2" << "ext2";
782     QTest::newRow("driveWithoutSlash") << "c:file1.ext1.ext2" << "ext2";
783 #endif
784 }
785 
suffix()786 void tst_QFileInfo::suffix()
787 {
788     QFETCH(QString, file);
789     QFETCH(QString, expected);
790 
791     QFileInfo fi(file);
792     QCOMPARE(fi.suffix(), expected);
793 }
794 
795 
completeSuffix_data()796 void tst_QFileInfo::completeSuffix_data()
797 {
798     QTest::addColumn<QString>("file");
799     QTest::addColumn<QString>("expected");
800 
801     QTest::newRow("noextension0") << "file" << "";
802     QTest::newRow("noextension1") << "/path/to/file" << "";
803     QTest::newRow("data0") << "file.tar" << "tar";
804     QTest::newRow("data1") << "file.tar.gz" << "tar.gz";
805     QTest::newRow("data2") << "/path/file/file.tar.gz" << "tar.gz";
806     QTest::newRow("data3") << "/path/file.tar" << "tar";
807     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "ext1";
808     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "ext1.ext2";
809 #ifdef Q_OS_WIN
810     QTest::newRow("driveWithSlash") << "c:/file1.ext1.ext2" << "ext1.ext2";
811     QTest::newRow("driveWithoutSlash") << "c:file1.ext1.ext2" << "ext1.ext2";
812 #endif
813 }
814 
completeSuffix()815 void tst_QFileInfo::completeSuffix()
816 {
817     QFETCH(QString, file);
818     QFETCH(QString, expected);
819 
820     QFileInfo fi(file);
821     QCOMPARE(fi.completeSuffix(), expected);
822 }
823 
baseName_data()824 void tst_QFileInfo::baseName_data()
825 {
826     QTest::addColumn<QString>("file");
827     QTest::addColumn<QString>("expected");
828 
829     QTest::newRow("data0") << "file.tar" << "file";
830     QTest::newRow("data1") << "file.tar.gz" << "file";
831     QTest::newRow("data2") << "/path/file/file.tar.gz" << "file";
832     QTest::newRow("data3") << "/path/file.tar" << "file";
833     QTest::newRow("data4") << "/path/file" << "file";
834     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "file1";
835     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "file1";
836 #ifdef Q_OS_WIN
837     QTest::newRow("driveWithSlash") << "c:/file1.ext1.ext2" << "file1";
838     QTest::newRow("driveWithoutSlash") << "c:file1.ext1.ext2" << "file1";
839 #endif
840 }
841 
baseName()842 void tst_QFileInfo::baseName()
843 {
844     QFETCH(QString, file);
845     QFETCH(QString, expected);
846 
847     QFileInfo fi(file);
848     QCOMPARE(fi.baseName(), expected);
849 }
850 
completeBaseName_data()851 void tst_QFileInfo::completeBaseName_data()
852 {
853     QTest::addColumn<QString>("file");
854     QTest::addColumn<QString>("expected");
855 
856     QTest::newRow("data0") << "file.tar" << "file";
857     QTest::newRow("data1") << "file.tar.gz" << "file.tar";
858     QTest::newRow("data2") << "/path/file/file.tar.gz" << "file.tar";
859     QTest::newRow("data3") << "/path/file.tar" << "file";
860     QTest::newRow("data4") << "/path/file" << "file";
861     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << "file1";
862     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << "file1.ext1";
863 #ifdef Q_OS_WIN
864     QTest::newRow("driveWithSlash") << "c:/file1.ext1.ext2" << "file1.ext1";
865     QTest::newRow("driveWithoutSlash") << "c:file1.ext1.ext2" << "file1.ext1";
866 #endif
867 }
868 
completeBaseName()869 void tst_QFileInfo::completeBaseName()
870 {
871     QFETCH(QString, file);
872     QFETCH(QString, expected);
873 
874     QFileInfo fi(file);
875     QCOMPARE(fi.completeBaseName(), expected);
876 }
877 
permission_data()878 void tst_QFileInfo::permission_data()
879 {
880     QTest::addColumn<QString>("file");
881     QTest::addColumn<int>("perms");
882     QTest::addColumn<bool>("expected");
883 
884     QTest::newRow("data0") << QCoreApplication::instance()->applicationFilePath() << int(QFile::ExeUser) << true;
885     QTest::newRow("data1") << SRCDIR "tst_qfileinfo.cpp" << int(QFile::ReadUser) << true;
886 //    QTest::newRow("data2") << "tst_qfileinfo.cpp" << int(QFile::WriteUser) << false;
887     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << int(QFile::ReadUser) << true;
888     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1" << int(QFile::WriteUser) << false;
889     QTest::newRow("resource3") << ":/tst_qfileinfo/resources/file1.ext1" << int(QFile::ExeUser) << false;
890 }
891 
permission()892 void tst_QFileInfo::permission()
893 {
894     QFETCH(QString, file);
895     QFETCH(int, perms);
896     QFETCH(bool, expected);
897 #ifdef Q_OS_SYMBIAN
898     QSKIP("No user based rights in Symbian OS - SOS needs platform security tests instead", SkipAll);
899 #endif
900     QFileInfo fi(file);
901     QCOMPARE(fi.permission(QFile::Permissions(perms)), expected);
902 }
903 
size_data()904 void tst_QFileInfo::size_data()
905 {
906     QTest::addColumn<QString>("file");
907     QTest::addColumn<int>("size");
908 
909     QTest::newRow("resource1") << ":/tst_qfileinfo/resources/file1.ext1" << 0;
910     QFile::remove("file1");
911     QFile file("file1");
912     QVERIFY(file.open(QFile::WriteOnly));
913     QCOMPARE(file.write("JAJAJAA"), qint64(7));
914     QTest::newRow("created-file") << "file1" << 7;
915 
916     QTest::newRow("resource2") << ":/tst_qfileinfo/resources/file1.ext1.ext2" << 0;
917 }
918 
size()919 void tst_QFileInfo::size()
920 {
921     QFETCH(QString, file);
922 
923     QFileInfo fi(file);
924     (void)fi.permissions();     // see task 104198
925     QTEST(int(fi.size()), "size");
926 }
927 
systemFiles()928 void tst_QFileInfo::systemFiles()
929 {
930 #if !defined(Q_OS_WIN) || defined(Q_OS_WINCE)
931     QSKIP("This is a Windows only test", SkipAll);
932 #endif
933     QFileInfo fi("c:\\pagefile.sys");
934     QVERIFY(fi.exists());      // task 167099
935     QVERIFY(fi.size() > 0);    // task 189202
936     QVERIFY(fi.lastModified().isValid());
937 }
938 
compare_data()939 void tst_QFileInfo::compare_data()
940 {
941     QTest::addColumn<QString>("file1");
942     QTest::addColumn<QString>("file2");
943     QTest::addColumn<bool>("same");
944 
945 #if defined(Q_OS_MAC)
946     // Since 10.6 we use realpath() in qfsfileengine, and it properly handles
947     // file system case sensitivity. However here in the autotest we don't
948     // check if the file system is case sensitive, so to make it pass in the
949     // default OS X installation we assume we are running on a case insensitive
950     // file system if on 10.6 and on a case sensitive file system if on 10.5
951     bool caseSensitiveOnMac = true;
952     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6)
953         caseSensitiveOnMac = false;
954 #endif
955 
956     QTest::newRow("data0")
957         << QString::fromLatin1(SRCDIR "tst_qfileinfo.cpp")
958         << QString::fromLatin1(SRCDIR "tst_qfileinfo.cpp")
959         << true;
960     QTest::newRow("data1")
961         << QString::fromLatin1(SRCDIR "tst_qfileinfo.cpp")
962         << QString::fromLatin1("/tst_qfileinfo.cpp")
963         << false;
964     QTest::newRow("data2")
965         << QString::fromLatin1("tst_qfileinfo.cpp")
966         << QDir::currentPath() + QString::fromLatin1("/tst_qfileinfo.cpp")
967         << true;
968     QTest::newRow("casesense1")
969         << QString::fromLatin1(SRCDIR "tst_qfileInfo.cpp")
970         << QString::fromLatin1(SRCDIR "tst_qfileinfo.cpp")
971 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
972         << true;
973 #elif defined(Q_OS_MAC)
974         << !caseSensitiveOnMac;
975 #else
976         << false;
977 #endif
978 }
979 
compare()980 void tst_QFileInfo::compare()
981 {
982     QFETCH(QString, file1);
983     QFETCH(QString, file2);
984     QFETCH(bool, same);
985     QFileInfo fi1(file1), fi2(file2);
986     QCOMPARE(fi1 == fi2, same);
987 }
988 
consistent_data()989 void tst_QFileInfo::consistent_data()
990 {
991     QTest::addColumn<QString>("file");
992     QTest::addColumn<QString>("expected");
993 
994 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
995     QTest::newRow("slashes") << QString::fromLatin1("\\a\\a\\a\\a") << QString::fromLatin1("/a/a/a/a");
996 #endif
997     QTest::newRow("ending slash") << QString::fromLatin1("/a/somedir/") << QString::fromLatin1("/a/somedir/");
998     QTest::newRow("no ending slash") << QString::fromLatin1("/a/somedir") << QString::fromLatin1("/a/somedir");
999 }
1000 
consistent()1001 void tst_QFileInfo::consistent()
1002 {
1003     QFETCH(QString, file);
1004     QFETCH(QString, expected);
1005 
1006     QFileInfo fi(file);
1007     QCOMPARE(fi.filePath(), expected);
1008     QCOMPARE(fi.dir().path() + "/" + fi.fileName(), expected);
1009 }
1010 
1011 
fileTimes_data()1012 void tst_QFileInfo::fileTimes_data()
1013 {
1014     QTest::addColumn<QString>("fileName");
1015     QTest::newRow("simple") << QString::fromLatin1("simplefile.txt");
1016     QTest::newRow( "longfile" ) << QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
1017                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1018                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1019                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1020                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt");
1021     QTest::newRow( "longfile absolutepath" ) << QFileInfo(QString::fromLatin1("longFileNamelongFileNamelongFileNamelongFileName"
1022                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1023                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1024                                                      "longFileNamelongFileNamelongFileNamelongFileName"
1025                                                      "longFileNamelongFileNamelongFileNamelongFileName.txt")).absoluteFilePath();
1026 }
1027 
fileTimes()1028 void tst_QFileInfo::fileTimes()
1029 {
1030 #if defined(Q_OS_WINCE)
1031     int sleepTime = 3000;
1032 #else
1033     int sleepTime = 2000;
1034 #endif
1035     QFETCH(QString, fileName);
1036     if (QFile::exists(fileName)) {
1037         QVERIFY(QFile::remove(fileName));
1038     }
1039     QTest::qSleep(sleepTime);
1040     {
1041         QFile file(fileName);
1042 #if defined(Q_OS_WINCE)
1043         QEXPECT_FAIL("longfile", "No long filenames on WinCE", Abort);
1044         QEXPECT_FAIL("longfile absolutepath", "No long filenames on WinCE", Abort);
1045 #elif defined(Q_OS_SYMBIAN)
1046         QEXPECT_FAIL("longfile", "Maximum total filepath cannot exceed 256 characters in Symbian", Abort);
1047         QEXPECT_FAIL("longfile absolutepath", "Maximum total filepath cannot exceed 256 characters in Symbian", Abort);
1048 #endif
1049         QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
1050 #ifdef Q_OS_UNIX
1051         if (qIsLikelyToBeNfs(file.handle()))
1052             QSKIP("This Test doesn't work on NFS", SkipAll);
1053 #endif
1054         QTextStream ts(&file);
1055         ts << fileName << endl;
1056     }
1057     QTest::qSleep(sleepTime);
1058     QDateTime beforeWrite = QDateTime::currentDateTime();
1059     QTest::qSleep(sleepTime);
1060     {
1061         QFileInfo fileInfo(fileName);
1062         QVERIFY(fileInfo.created() < beforeWrite);
1063         QFile file(fileName);
1064         QVERIFY(file.open(QFile::ReadWrite | QFile::Text));
1065         QTextStream ts(&file);
1066         ts << fileName << endl;
1067     }
1068     QTest::qSleep(sleepTime);
1069     QDateTime beforeRead = QDateTime::currentDateTime();
1070     QTest::qSleep(sleepTime);
1071     {
1072         QFileInfo fileInfo(fileName);
1073 // On unix created() returns the same as lastModified().
1074 #if !defined(Q_OS_UNIX) && !defined(Q_OS_WINCE)
1075         QVERIFY(fileInfo.created() < beforeWrite);
1076 #endif
1077         QVERIFY(fileInfo.lastModified() > beforeWrite);
1078         QFile file(fileName);
1079         QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
1080         QTextStream ts(&file);
1081         QString line = ts.readLine();
1082         QCOMPARE(line, fileName);
1083     }
1084 
1085     QFileInfo fileInfo(fileName);
1086 #if !defined(Q_OS_UNIX) && !defined(Q_OS_WINCE)
1087     QVERIFY(fileInfo.created() < beforeWrite);
1088 #endif
1089     //In Vista the last-access timestamp is not updated when the file is accessed/touched (by default).
1090     //To enable this the HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate
1091     //is set to 0, in the test machine.
1092 #ifdef Q_OS_WIN
1093     HKEY key;
1094     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\FileSystem",
1095         0, KEY_READ, &key)) {
1096             DWORD disabledAccessTimes = 0;
1097             DWORD size = sizeof(DWORD);
1098             LONG error = RegQueryValueEx(key, L"NtfsDisableLastAccessUpdate"
1099                 , NULL, NULL, (LPBYTE)&disabledAccessTimes, &size);
1100             if (ERROR_SUCCESS == error && disabledAccessTimes)
1101                 QEXPECT_FAIL("", "File access times are disabled in windows registry (this is the default setting)", Continue);
1102             RegCloseKey(key);
1103     }
1104 #endif
1105 #if defined(Q_OS_WINCE)
1106     QEXPECT_FAIL("simple", "WinCE only stores date of access data, not the time", Continue);
1107 #elif defined(Q_OS_SYMBIAN)
1108     QEXPECT_FAIL("simple", "Symbian implementation of stat doesn't return read time right", Abort);
1109 #elif defined(Q_OS_BLACKBERRY)
1110     QEXPECT_FAIL("simple", "Blackberry OS uses the noatime filesystem option", Continue);
1111     QEXPECT_FAIL("longfile", "Blackberry OS uses the noatime filesystem option", Continue);
1112     QEXPECT_FAIL("longfile absolutepath", "Blackberry OS uses the noatime filesystem option", Continue);
1113 #endif
1114     QVERIFY(fileInfo.lastRead() > beforeRead);
1115     QVERIFY(fileInfo.lastModified() > beforeWrite);
1116     QVERIFY(fileInfo.lastModified() < beforeRead);
1117 }
1118 
fileTimes_oldFile()1119 void tst_QFileInfo::fileTimes_oldFile()
1120 {
1121     // This is not supported on WinCE
1122 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1123     // All files are opened in share mode (both read and write).
1124     DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
1125 
1126     // All files on Windows can be read; there's no such thing as an
1127     // unreadable file. Add GENERIC_WRITE if WriteOnly is passed.
1128     int accessRights = GENERIC_READ | GENERIC_WRITE;
1129 
1130     SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
1131 
1132     // Regular file mode. In Unbuffered mode, pass the no-buffering flag.
1133     DWORD flagsAndAtts = FILE_ATTRIBUTE_NORMAL;
1134 
1135     // WriteOnly can create files, ReadOnly cannot.
1136     DWORD creationDisp = OPEN_ALWAYS;
1137 
1138     // Create the file handle.
1139     HANDLE fileHandle = CreateFile(L"oldfile.txt",
1140         accessRights,
1141         shareMode,
1142         &securityAtts,
1143         creationDisp,
1144         flagsAndAtts,
1145         NULL);
1146 
1147     // Set file times back to 1601.
1148     SYSTEMTIME stime;
1149     stime.wYear = 1601;
1150     stime.wMonth = 1;
1151     stime.wDayOfWeek = 1;
1152     stime.wDay = 1;
1153     stime.wHour = 1;
1154     stime.wMinute = 0;
1155     stime.wSecond = 0;
1156     stime.wMilliseconds = 0;
1157 
1158     FILETIME ctime;
1159     QVERIFY(SystemTimeToFileTime(&stime, &ctime));
1160     FILETIME atime = ctime;
1161     FILETIME mtime = atime;
1162     QVERIFY(fileHandle);
1163     QVERIFY(SetFileTime(fileHandle, &ctime, &atime, &mtime) != 0);
1164 
1165     CloseHandle(fileHandle);
1166 
1167     QFileInfo info("oldfile.txt");
1168     QCOMPARE(info.lastModified(), QDateTime(QDate(1601, 1, 1), QTime(1, 0), Qt::UTC).toLocalTime());
1169 #endif
1170 }
1171 
isSymLink_data()1172 void tst_QFileInfo::isSymLink_data()
1173 {
1174 #ifndef NO_SYMLINKS
1175     QFile::remove("link.lnk");
1176     QFile::remove("brokenlink.lnk");
1177     QFile::remove("dummyfile");
1178 
1179     QFile file1(SRCDIR "tst_qfileinfo.cpp");
1180     QVERIFY(file1.link("link.lnk"));
1181 
1182     QFile file2("dummyfile");
1183     file2.open(QIODevice::WriteOnly);
1184     QVERIFY(file2.link("brokenlink.lnk"));
1185     file2.remove();
1186 
1187     QTest::addColumn<QString>("path");
1188     QTest::addColumn<bool>("isSymLink");
1189     QTest::addColumn<QString>("linkTarget");
1190 
1191     QTest::newRow("existent file") << SRCDIR "tst_qfileinfo.cpp" << false << "";
1192     QTest::newRow("link") << "link.lnk" << true << QFileInfo(SRCDIR "tst_qfileinfo.cpp").absoluteFilePath();
1193     QTest::newRow("broken link") << "brokenlink.lnk" << true << QFileInfo("dummyfile").absoluteFilePath();
1194 #endif
1195 }
1196 
isSymLink()1197 void tst_QFileInfo::isSymLink()
1198 {
1199 #ifndef NO_SYMLINKS
1200     QFETCH(QString, path);
1201     QFETCH(bool, isSymLink);
1202     QFETCH(QString, linkTarget);
1203 
1204     QFileInfo fi(path);
1205     QCOMPARE(fi.isSymLink(), isSymLink);
1206     QCOMPARE(fi.symLinkTarget(), linkTarget);
1207 #else
1208     QSKIP("no symbolic link support on this platform", SkipAll);
1209 #endif
1210 }
1211 
isHidden_data()1212 void tst_QFileInfo::isHidden_data()
1213 {
1214     QTest::addColumn<QString>("path");
1215     QTest::addColumn<bool>("isHidden");
1216     foreach (const QFileInfo& info, QDir::drives()) {
1217         QTest::newRow(qPrintable("drive." + info.path())) << info.path() << false;
1218     }
1219 
1220 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1221     QVERIFY(QDir("./hidden-directory").exists() || QDir().mkdir("./hidden-directory"));
1222     QVERIFY(SetFileAttributesW(reinterpret_cast<LPCWSTR>(QString("./hidden-directory").utf16()),FILE_ATTRIBUTE_HIDDEN));
1223     QTest::newRow("C:/path/to/hidden-directory") << QDir::currentPath() + QString::fromLatin1("/hidden-directory") << true;
1224     QTest::newRow("C:/path/to/hidden-directory/.") << QDir::currentPath() + QString::fromLatin1("/hidden-directory/.") << true;
1225 #endif
1226 #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
1227     QVERIFY(QDir("./.hidden-directory").exists() || QDir().mkdir("./.hidden-directory"));
1228     QTest::newRow("/path/to/.hidden-directory") << QDir::currentPath() + QString("/.hidden-directory") << true;
1229     QTest::newRow("/path/to/.hidden-directory/.") << QDir::currentPath() + QString("/.hidden-directory/.") << true;
1230     QTest::newRow("/path/to/.hidden-directory/..") << QDir::currentPath() + QString("/.hidden-directory/..") << true;
1231 #endif
1232 
1233 #if defined(Q_OS_MAC)
1234     // /bin has the hidden attribute on Mac OS X
1235     QTest::newRow("/bin/") << QString::fromLatin1("/bin/") << true;
1236 #elif !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN)
1237     QTest::newRow("/bin/") << QString::fromLatin1("/bin/") << false;
1238 #endif
1239 
1240 #ifdef Q_OS_MAC
1241     QTest::newRow("mac_etc") << QString::fromLatin1("/etc") << true;
1242     QTest::newRow("mac_private_etc") << QString::fromLatin1("/private/etc") << false;
1243     QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications") << false;
1244 #endif
1245 
1246 #ifdef Q_OS_SYMBIAN
1247     // No guaranteed hidden file knows to exist in Symbian filesystem, so make one.
1248     QString hiddenFileName("hidden.txt");
1249     QString notHiddenFileName("nothidden.txt");
1250     QTest::newRow("hidden file") << hiddenFileName << true;
1251     QTest::newRow("non-hidden file") << notHiddenFileName << false;
1252 
1253     {
1254         QFile file(hiddenFileName);
1255         QVERIFY(file.open(QIODevice::WriteOnly));
1256         QTextStream t(&file);
1257         t << "foobar";
1258 
1259         QFile file2(notHiddenFileName);
1260         QVERIFY(file2.open(QIODevice::WriteOnly));
1261         QTextStream t2(&file2);
1262         t2 << "foobar";
1263     }
1264 
1265     RFs rfs;
1266     TInt err = rfs.Connect();
1267     QCOMPARE(err, KErrNone);
1268     HBufC* symFile = qt_QString2HBufC(hiddenFileName);
1269     err = rfs.SetAtt(*symFile, KEntryAttHidden, 0);
1270     rfs.Close();
1271     delete symFile;
1272     QCOMPARE(err, KErrNone);
1273 #endif
1274 }
1275 
isHidden()1276 void tst_QFileInfo::isHidden()
1277 {
1278     QFETCH(QString, path);
1279     QFETCH(bool, isHidden);
1280     QFileInfo fi(path);
1281 
1282     QCOMPARE(fi.isHidden(), isHidden);
1283 }
1284 
1285 #if defined(Q_OS_MAC)
isHiddenFromFinder()1286 void tst_QFileInfo::isHiddenFromFinder()
1287 {
1288     const char *filename = "test_foobar.txt";
1289 
1290     QFile testFile(filename);
1291     testFile.open(QIODevice::WriteOnly | QIODevice::Append);
1292     testFile.write(QByteArray("world"));
1293     testFile.close();
1294 
1295     struct stat buf;
1296     stat(filename, &buf);
1297     chflags(filename, buf.st_flags | UF_HIDDEN);
1298 
1299     QFileInfo fi(filename);
1300     QCOMPARE(fi.isHidden(), true);
1301 
1302     testFile.remove();
1303 }
1304 #endif
1305 
isBundle_data()1306 void tst_QFileInfo::isBundle_data()
1307 {
1308     QTest::addColumn<QString>("path");
1309     QTest::addColumn<bool>("isBundle");
1310     QTest::newRow("root") << QString::fromLatin1("/") << false;
1311 #ifdef Q_OS_MAC
1312     QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications") << false;
1313     QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications/Safari.app") << true;
1314 #endif
1315 }
1316 
isBundle()1317 void tst_QFileInfo::isBundle()
1318 {
1319     QFETCH(QString, path);
1320     QFETCH(bool, isBundle);
1321     QFileInfo fi(path);
1322     QCOMPARE(fi.isBundle(), isBundle);
1323 }
1324 
isLocalFs_data()1325 void tst_QFileInfo::isLocalFs_data()
1326 {
1327     QTest::addColumn<QString>("path");
1328     QTest::addColumn<bool>("isLocalFs");
1329 
1330     QTest::newRow("local root") << QString::fromLatin1("/") << true;
1331     QTest::newRow("local non-existent file") << QString::fromLatin1("/abrakadabra.boo") << true;
1332 
1333     QTest::newRow("qresource root") << QString::fromLatin1(":/") << false;
1334 }
1335 
isLocalFs()1336 void tst_QFileInfo::isLocalFs()
1337 {
1338     QFETCH(QString, path);
1339     QFETCH(bool, isLocalFs);
1340 
1341     QFileInfo info(path);
1342     QFileInfoPrivate *privateInfo = getPrivate(info);
1343     QCOMPARE((privateInfo->fileEngine == 0), isLocalFs);
1344     if (privateInfo->fileEngine)
1345        QCOMPARE(bool(privateInfo->fileEngine->fileFlags(QAbstractFileEngine::LocalDiskFlag)
1346                      & QAbstractFileEngine::LocalDiskFlag), isLocalFs);
1347 }
1348 
refresh()1349 void tst_QFileInfo::refresh()
1350 {
1351 #if defined(Q_OS_WINCE) || defined(Q_OS_WIN)
1352     int sleepTime = 3000;
1353 #else
1354     int sleepTime = 2000;
1355 #endif
1356 
1357     QFile::remove("file1");
1358     QFile file("file1");
1359     QVERIFY(file.open(QFile::WriteOnly));
1360     QCOMPARE(file.write("JAJAJAA"), qint64(7));
1361     file.flush();
1362 
1363     QFileInfo info(file);
1364     QDateTime lastModified = info.lastModified();
1365     QCOMPARE(info.size(), qint64(7));
1366 
1367     QTest::qSleep(sleepTime);
1368 
1369     QCOMPARE(file.write("JOJOJO"), qint64(6));
1370     file.flush();
1371     QVERIFY(info.lastModified() == lastModified);
1372 
1373     QCOMPARE(info.size(), qint64(7));
1374 #if defined(Q_OS_WIN) || defined(Q_OS_WINCE)
1375     if (QSysInfo::windowsVersion() & QSysInfo::WV_VISTA ||
1376                 QSysInfo::windowsVersion() & QSysInfo::WV_CE_based)
1377         file.close();
1378 #endif
1379 #if defined(Q_OS_WINCE)
1380     // On Windows CE we need to close the file.
1381     // Otherwise the content will be cached and not
1382     // flushed to the storage, although we flushed it
1383     // manually!!! CE has interim cache, we cannot influence.
1384     QTest::qWait(5000);
1385 #endif
1386     info.refresh();
1387     QCOMPARE(info.size(), qint64(13));
1388     QVERIFY(info.lastModified() > lastModified);
1389 
1390     QFileInfo info2 = info;
1391     QCOMPARE(info2.size(), info.size());
1392 
1393     info2.refresh();
1394     QCOMPARE(info2.size(), info.size());
1395 }
1396 
1397 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
ntfsJunctionPointsAndSymlinks_data()1398 void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
1399 {
1400     QTest::addColumn<QString>("path");
1401     QTest::addColumn<bool>("isSymLink");
1402     QTest::addColumn<QString>("linkTarget");
1403     QTest::addColumn<QString>("canonicalFilePath");
1404 
1405     QDir pwd;
1406     pwd.mkdir("target");
1407 
1408     QLibrary kernel32("kernel32");
1409     typedef BOOLEAN (WINAPI *PtrCreateSymbolicLink)(LPCWSTR, LPCWSTR, DWORD);
1410     PtrCreateSymbolicLink createSymbolicLinkW = 0;
1411     createSymbolicLinkW = (PtrCreateSymbolicLink) kernel32.resolve("CreateSymbolicLinkW");
1412     if (!createSymbolicLinkW) {
1413         //we need at least one data set for the test not to fail when skipping _data function
1414         QDir target("target");
1415         QTest::newRow("dummy") << target.path() << false << "" << target.canonicalPath();
1416         QSKIP("symbolic links not supported by operating system",SkipSingle);
1417     }
1418     {
1419         //Directory symlinks
1420         QDir target("target");
1421         QVERIFY(target.exists());
1422 
1423         QString absTarget = QDir::toNativeSeparators(target.absolutePath());
1424         QString absSymlink = QDir::toNativeSeparators(pwd.absolutePath()).append("\\abs_symlink");
1425         QString relTarget = "target";
1426         QString relSymlink = "rel_symlink";
1427         QString fileInTarget(absTarget);
1428         fileInTarget.append("\\file");
1429         QString fileInSymlink(absSymlink);
1430         fileInSymlink.append("\\file");
1431         QFile file(fileInTarget);
1432         file.open(QIODevice::ReadWrite);
1433         file.close();
1434 
1435         DWORD err = ERROR_SUCCESS ;
1436         if (!pwd.exists("abs_symlink"))
1437             if (!createSymbolicLinkW((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x1))
1438                 err = GetLastError();
1439         if (err == ERROR_SUCCESS && !pwd.exists(relSymlink))
1440             if (!createSymbolicLinkW((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x1))
1441                 err = GetLastError();
1442         if (err != ERROR_SUCCESS) {
1443             wchar_t errstr[0x100];
1444             DWORD count = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
1445                 0, err, 0, errstr, 0x100, 0);
1446             QString error(QString::fromWCharArray (errstr, count));
1447             qWarning() << error;
1448             //we need at least one data set for the test not to assert fail when skipping _data function
1449             QDir target("target");
1450             QTest::newRow("dummy") << target.path() << false << "" << target.canonicalPath();
1451             QSKIP("link not supported by FS or insufficient privilege", SkipSingle);
1452         }
1453         QVERIFY(file.exists());
1454 
1455         QTest::newRow("absolute dir symlink") << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalPath();
1456         QTest::newRow("relative dir symlink") << relSymlink << true << QDir::fromNativeSeparators(relTarget) << target.canonicalPath();
1457         QTest::newRow("file in symlink dir") << fileInSymlink << false << "" << target.canonicalPath().append("/file");
1458     }
1459     {
1460         //File symlinks
1461         QFileInfo target(SRCDIR "tst_qfileinfo.cpp");
1462         QString absTarget = QDir::toNativeSeparators(target.absoluteFilePath());
1463         QString absSymlink = QDir::toNativeSeparators(pwd.absolutePath()).append("\\abs_symlink.cpp");
1464         QString relTarget = QDir::toNativeSeparators(pwd.relativeFilePath(target.absoluteFilePath()));
1465         QString relSymlink = "rel_symlink.cpp";
1466         QVERIFY(pwd.exists("abs_symlink.cpp") || createSymbolicLinkW((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x0));
1467         QVERIFY(pwd.exists(relSymlink) || createSymbolicLinkW((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x0));
1468 
1469         QTest::newRow("absolute file symlink") << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
1470         QTest::newRow("relative file symlink") << relSymlink << true << QDir::fromNativeSeparators(relTarget) << target.canonicalFilePath();
1471     }
1472 
1473     //Junctions
1474     QString target = "target";
1475     QString junction = "junction_pwd";
1476     FileSystem::createNtfsJunction(target, junction);
1477     QFileInfo targetInfo(target);
1478     QTest::newRow("junction_pwd") << junction << false << QString() << QString();
1479 
1480     QFileInfo fileInJunction(targetInfo.absoluteFilePath().append("/file"));
1481     QFile file(fileInJunction.absoluteFilePath());
1482     file.open(QIODevice::ReadWrite);
1483     file.close();
1484     QVERIFY(file.exists());
1485     QTest::newRow("file in junction") << fileInJunction.absoluteFilePath() << false << "" << fileInJunction.canonicalFilePath();
1486 
1487     target = QDir::rootPath();
1488     junction = "junction_root";
1489     FileSystem::createNtfsJunction(target, junction);
1490     targetInfo.setFile(target);
1491     QTest::newRow("junction_root") << junction << false << QString() << QString();
1492 
1493     //Mountpoint
1494     typedef BOOLEAN (WINAPI *PtrGetVolumeNameForVolumeMountPointW)(LPCWSTR, LPWSTR, DWORD);
1495     PtrGetVolumeNameForVolumeMountPointW getVolumeNameForVolumeMountPointW = 0;
1496     getVolumeNameForVolumeMountPointW = (PtrGetVolumeNameForVolumeMountPointW) kernel32.resolve("GetVolumeNameForVolumeMountPointW");
1497     if(getVolumeNameForVolumeMountPointW)
1498     {
1499         wchar_t buffer[MAX_PATH];
1500         QString rootPath = QDir::toNativeSeparators(QDir::rootPath());
1501         QVERIFY(getVolumeNameForVolumeMountPointW((wchar_t*)rootPath.utf16(), buffer, MAX_PATH));
1502         QString rootVolume = QString::fromWCharArray(buffer);
1503         junction = "mountpoint";
1504         rootVolume.replace("\\\\?\\","\\??\\");
1505         FileSystem::createNtfsJunction(rootVolume, junction);
1506         QTest::newRow("mountpoint") << junction << false << QString() << QString();
1507     }
1508 }
1509 
ntfsJunctionPointsAndSymlinks()1510 void tst_QFileInfo::ntfsJunctionPointsAndSymlinks()
1511 {
1512     QFETCH(QString, path);
1513     QFETCH(bool, isSymLink);
1514     QFETCH(QString, linkTarget);
1515     QFETCH(QString, canonicalFilePath);
1516 
1517     QFileInfo fi(path);
1518     QCOMPARE(fi.isSymLink(), isSymLink);
1519     if (isSymLink) {
1520         QCOMPARE(fi.symLinkTarget(), linkTarget);
1521         QCOMPARE(fi.canonicalFilePath(), canonicalFilePath);
1522     }
1523 }
1524 
brokenShortcut()1525 void tst_QFileInfo::brokenShortcut()
1526 {
1527     QString linkName("borkenlink.lnk");
1528     QFile::remove(linkName);
1529     QFile file(linkName);
1530     file.open(QFile::WriteOnly);
1531     file.write("b0rk");
1532     file.close();
1533 
1534     QFileInfo info(linkName);
1535     QVERIFY(info.isSymLink());
1536     QVERIFY(!info.exists());
1537     QFile::remove(linkName);
1538 
1539     QDir current; // QTBUG-21863
1540     QVERIFY(current.mkdir(linkName));
1541     QFileInfo dirInfo(linkName);
1542     QVERIFY(!dirInfo.isSymLink());
1543     QVERIFY(dirInfo.isDir());
1544     current.rmdir(linkName);
1545 }
1546 #endif
1547 
isWritable()1548 void tst_QFileInfo::isWritable()
1549 {
1550     QFile tempfile("tempfile.txt");
1551     tempfile.open(QIODevice::WriteOnly);
1552     tempfile.write("This file is generated by the QFileInfo autotest.");
1553     tempfile.close();
1554 
1555     QVERIFY(QFileInfo("tempfile.txt").isWritable());
1556     tempfile.remove();
1557 
1558 #ifdef Q_OS_WIN
1559 #ifdef Q_OS_WINCE
1560     QFileInfo fi("\\Windows\\wince.nls");
1561 #else
1562     QFileInfo fi("c:\\pagefile.sys");
1563 #endif
1564     QVERIFY(fi.exists());
1565     QVERIFY(!fi.isWritable());
1566 #endif
1567 #if defined (Q_OS_BLACKBERRY)
1568     // The Blackberry filesystem is read-only
1569     QVERIFY(!QFileInfo("/etc/passwd").isWritable());
1570 #elif defined (Q_OS_UNIX) && !defined (Q_OS_SYMBIAN)
1571     if (::getuid() == 0)
1572         QVERIFY(QFileInfo("/etc/passwd").isWritable());
1573     else
1574         QVERIFY(!QFileInfo("/etc/passwd").isWritable());
1575 #endif
1576 }
1577 
isExecutable()1578 void tst_QFileInfo::isExecutable()
1579 {
1580 #ifdef Q_OS_SYMBIAN
1581     QString appPath = "c:/sys/bin/tst_qfileinfo.exe";
1582 #else
1583     QString appPath = QCoreApplication::applicationDirPath();
1584     appPath += "/tst_qfileinfo";
1585 # if defined(Q_OS_WIN)
1586     appPath += ".exe";
1587 # endif
1588 #endif
1589     QFileInfo fi(appPath);
1590     QCOMPARE(fi.isExecutable(), true);
1591 
1592     QCOMPARE(QFileInfo("qfileinfo.pro").isExecutable(), false);
1593 }
1594 
1595 
testDecomposedUnicodeNames_data()1596 void tst_QFileInfo::testDecomposedUnicodeNames_data()
1597 {
1598     QTest::addColumn<QString>("filePath");
1599     QTest::addColumn<QString>("fileName");
1600     QTest::addColumn<bool>("exists");
1601     QString currPath = QDir::currentPath();
1602     QTest::newRow("latin-only") << currPath + "/4.pdf" << "4.pdf" << true;
1603     QTest::newRow("one-decomposed uni") << currPath + QString::fromUtf8("/4 ä.pdf") << QString::fromUtf8("4 ä.pdf") << true;
1604     QTest::newRow("many-decomposed uni") << currPath + QString::fromUtf8("/4 äääcopy.pdf") << QString::fromUtf8("4 äääcopy.pdf") << true;
1605     QTest::newRow("no decomposed") << currPath + QString::fromUtf8("/4 øøøcopy.pdf") << QString::fromUtf8("4 øøøcopy.pdf") << true;
1606 }
1607 
createFileNative(const QString & filePath)1608 static void createFileNative(const QString &filePath)
1609 {
1610 #ifdef Q_OS_UNIX
1611     int fd = open(filePath.normalized(QString::NormalizationForm_D).toUtf8().constData(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
1612     if (fd < 0) {
1613         QFAIL("couldn't create file");
1614     } else {
1615         close(fd);
1616     }
1617 #else
1618     Q_UNUSED(filePath);
1619 #endif
1620 }
1621 
removeFileNative(const QString & filePath)1622 static void removeFileNative(const QString &filePath)
1623 {
1624 #ifdef Q_OS_UNIX
1625     unlink(filePath.normalized(QString::NormalizationForm_D).toUtf8().constData());
1626 #else
1627     Q_UNUSED(filePath);
1628 #endif
1629 }
1630 
testDecomposedUnicodeNames()1631 void tst_QFileInfo::testDecomposedUnicodeNames()
1632 {
1633 #ifndef Q_OS_MAC
1634     QSKIP("This is a OS X only test (unless you know more about filesystems, then maybe you should try it ;)", SkipAll);
1635 #endif
1636     QFETCH(QString, filePath);
1637     createFileNative(filePath);
1638 
1639     QFileInfo file(filePath);
1640     QTEST(file.fileName(), "fileName");
1641     QTEST(file.exists(), "exists");
1642     removeFileNative(filePath);
1643 }
1644 
equalOperator() const1645 void tst_QFileInfo::equalOperator() const
1646 {
1647     /* Compare two default constructed values. Yes, to me it seems it should be the opposite too, but
1648      * this is how the code was written. */
1649     QVERIFY(!(QFileInfo() == QFileInfo()));
1650 }
1651 
1652 
equalOperatorWithDifferentSlashes() const1653 void tst_QFileInfo::equalOperatorWithDifferentSlashes() const
1654 {
1655     const QFileInfo fi1("/usr");
1656     const QFileInfo fi2("/usr/");
1657 
1658     QCOMPARE(fi1, fi2);
1659 }
1660 
notEqualOperator() const1661 void tst_QFileInfo::notEqualOperator() const
1662 {
1663     /* Compare two default constructed values. Yes, to me it seems it should be the opposite too, but
1664      * this is how the code was written. */
1665     QVERIFY(QFileInfo() != QFileInfo());
1666 }
1667 
detachingOperations()1668 void tst_QFileInfo::detachingOperations()
1669 {
1670     QFileInfo info1;
1671     QVERIFY(info1.caching());
1672     info1.setCaching(false);
1673 
1674     {
1675         QFileInfo info2 = info1;
1676 
1677         QVERIFY(!info1.caching());
1678         QVERIFY(!info2.caching());
1679 
1680         info2.setCaching(true);
1681         QVERIFY(info2.caching());
1682 
1683         info1.setFile("foo");
1684         QVERIFY(!info1.caching());
1685     }
1686 
1687     {
1688         QFile file("foo");
1689         info1.setFile(file);
1690         QVERIFY(!info1.caching());
1691     }
1692 
1693     info1.setFile(QDir(), "foo");
1694     QVERIFY(!info1.caching());
1695 
1696     {
1697         QFileInfo info3;
1698         QVERIFY(info3.caching());
1699 
1700         info3 = info1;
1701         QVERIFY(!info3.caching());
1702     }
1703 
1704     info1.refresh();
1705     QVERIFY(!info1.caching());
1706 
1707     QVERIFY(info1.makeAbsolute());
1708     QVERIFY(!info1.caching());
1709 
1710     info1.detach();
1711     QVERIFY(!info1.caching());
1712 }
1713 
1714 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
1715 #if defined (Q_OS_WIN)
IsUserAdmin()1716 BOOL IsUserAdmin()
1717 {
1718     BOOL b;
1719     SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
1720     PSID AdministratorsGroup;
1721     b = AllocateAndInitializeSid(
1722                 &NtAuthority,
1723                 2,
1724                 SECURITY_BUILTIN_DOMAIN_RID,
1725                 DOMAIN_ALIAS_RID_ADMINS,
1726                 0, 0, 0, 0, 0, 0,
1727                 &AdministratorsGroup);
1728     if (b) {
1729         if (!CheckTokenMembership( NULL, AdministratorsGroup, &b))
1730             b = FALSE;
1731         FreeSid(AdministratorsGroup);
1732     }
1733 
1734     return(b);
1735 }
1736 #endif
1737 
owner()1738 void tst_QFileInfo::owner()
1739 {
1740     QString userName;
1741 #if defined(Q_OS_UNIX)
1742     {
1743         passwd *user = getpwuid(geteuid());
1744         QVERIFY(user);
1745         char *usernameBuf = user->pw_name;
1746         userName = QString::fromLocal8Bit(usernameBuf);
1747     }
1748 #endif
1749 #if defined(Q_OS_WIN)
1750     wchar_t  usernameBuf[1024];
1751     DWORD  bufSize = 1024;
1752     if (GetUserNameW(usernameBuf, &bufSize)) {
1753         userName = QString::fromWCharArray(usernameBuf);
1754         if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && IsUserAdmin()) {
1755             // Special case : If the user is a member of Administrators group, all files
1756             // created by the current user are owned by the Administrators group.
1757             LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
1758             DWORD dwLevel = 0;
1759             DWORD dwFlags = LG_INCLUDE_INDIRECT ;
1760             DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
1761             DWORD dwEntriesRead = 0;
1762             DWORD dwTotalEntries = 0;
1763             NET_API_STATUS nStatus;
1764             nStatus = NetUserGetLocalGroups(0, usernameBuf, dwLevel, dwFlags, (LPBYTE *) &pBuf,
1765                                             dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries);
1766             // Check if the current user is a member of Administrators group
1767             if (nStatus == NERR_Success && pBuf){
1768                 for (int i = 0; i < (int)dwEntriesRead; i++) {
1769                     QString groupName = QString::fromWCharArray(pBuf[i].lgrui0_name);
1770                     if (!groupName.compare(QLatin1String("Administrators")))
1771                         userName = groupName;
1772                 }
1773             }
1774             if (pBuf != NULL)
1775                 NetApiBufferFree(pBuf);
1776         }
1777     }
1778     extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
1779     qt_ntfs_permission_lookup = 1;
1780 #endif
1781     if (userName.isEmpty())
1782         QSKIP("Can't retrieve the user name", SkipAll);
1783     QString fileName("ownertest.txt");
1784     QVERIFY(!QFile::exists(fileName) || QFile::remove(fileName));
1785     {
1786         QFile testFile(fileName);
1787         QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text));
1788         QByteArray testData("testfile");
1789         QVERIFY(testFile.write(testData) != -1);
1790     }
1791     QFileInfo fi(fileName);
1792     QVERIFY(fi.exists());
1793     QCOMPARE(fi.owner(), userName);
1794 
1795     QFile::remove(fileName);
1796 #if defined(Q_OS_WIN)
1797     qt_ntfs_permission_lookup = 0;
1798 #endif
1799 }
1800 #endif
1801 
group()1802 void tst_QFileInfo::group()
1803 {
1804     QString expected;
1805 #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
1806     struct group *gr;
1807     gid_t gid = getegid();
1808     gr = getgrgid(gid);
1809     expected = QString::fromLocal8Bit(gr->gr_name);
1810 #endif
1811 
1812     QString fileName("ownertest.txt");
1813     if (QFile::exists(fileName))
1814         QFile::remove(fileName);
1815     QFile testFile(fileName);
1816     QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Text));
1817     QByteArray testData("testfile");
1818     QVERIFY(testFile.write(testData) != -1);
1819     testFile.close();
1820     QFileInfo fi(fileName);
1821     QVERIFY(fi.exists());
1822 
1823     QCOMPARE(fi.group(), expected);
1824 }
1825 
invalidState()1826 void tst_QFileInfo::invalidState()
1827 {
1828     // Shouldn't crash;
1829 
1830     {
1831         QFileInfo info;
1832         QCOMPARE(info.size(), qint64(0));
1833         QVERIFY(!info.exists());
1834 
1835         info.setCaching(false);
1836 
1837         info.created();
1838         info.lastRead();
1839         info.lastModified();
1840     }
1841 
1842     {
1843         QFileInfo info("");
1844         QCOMPARE(info.size(), qint64(0));
1845         QVERIFY(!info.exists());
1846 
1847         info.setCaching(false);
1848 
1849         info.created();
1850         info.lastRead();
1851         info.lastModified();
1852     }
1853 
1854     {
1855         QFileInfo info("file-doesn't-really-exist.txt");
1856         QCOMPARE(info.size(), qint64(0));
1857         QVERIFY(!info.exists());
1858 
1859         info.setCaching(false);
1860 
1861         info.created();
1862         info.lastRead();
1863         info.lastModified();
1864     }
1865 
1866     QVERIFY(true);
1867 }
1868 
1869 QTEST_MAIN(tst_QFileInfo)
1870 #include "tst_qfileinfo.moc"
1871