summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp')
-rw-r--r--tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp417
1 files changed, 249 insertions, 168 deletions
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index 09113cd40b..f7d531f61f 100644
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -1,35 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QStandardPaths>
#include <QScopeGuard>
-#include <QScopedValueRollback>
#include <qfile.h>
#include <qdir.h>
@@ -56,23 +31,23 @@
#endif
#include <qplatformdefs.h>
#include <qdebug.h>
-#if defined(Q_OS_WIN)
-#include "../../../network-settings.h"
-#endif
#include <private/qfileinfo_p.h>
#include "../../../../shared/filesystem.h"
+#if defined(Q_OS_MACOS)
+#include <Foundation/Foundation.h>
+#endif
+
#if defined(Q_OS_VXWORKS)
#define Q_NO_SYMLINKS
#endif
#if defined(Q_OS_WIN)
-QT_BEGIN_NAMESPACE
-extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
-QT_END_NAMESPACE
bool IsUserAdmin();
#endif
+using namespace Qt::StringLiterals;
+
inline bool qIsLikelyToBeFat(const QString &path)
{
QByteArray name = QStorageInfo(path).fileSystemType().toLower();
@@ -96,31 +71,6 @@ inline bool qIsLikelyToBeNfs(const QString &path)
}
#if defined(Q_OS_WIN)
-# ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE // MinGW
-# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
-# endif
-
-static DWORD createSymbolicLink(const QString &symLinkName, const QString &target,
- QString *errorMessage)
-{
- DWORD result = ERROR_SUCCESS;
- const QString nativeSymLinkName = QDir::toNativeSeparators(symLinkName);
- const QString nativeTarget = QDir::toNativeSeparators(target);
- DWORD flags = 0;
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14972))
- flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
- if (QFileInfo(target).isDir())
- flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
- if (CreateSymbolicLink(reinterpret_cast<const wchar_t*>(nativeSymLinkName.utf16()),
- reinterpret_cast<const wchar_t*>(nativeTarget.utf16()), flags) == FALSE) {
- result = GetLastError();
- QTextStream(errorMessage) << "CreateSymbolicLink(" << nativeSymLinkName << ", "
- << nativeTarget << ", 0x" << Qt::hex << flags << Qt::dec << ") failed with error " << result
- << ": " << qt_error_string(int(result));
- }
- return result;
-}
-
static QByteArray msgInsufficientPrivileges(const QString &errorMessage)
{
return "Insufficient privileges (" + errorMessage.toLocal8Bit() + ')';
@@ -223,6 +173,7 @@ private slots:
void systemFiles();
+ void compareCompiles();
void compare_data();
void compare();
@@ -231,6 +182,7 @@ private slots:
void fileTimes_data();
void fileTimes();
+ void setFileTimes();
void fakeFileTimes_data();
void fakeFileTimes();
@@ -243,12 +195,15 @@ private slots:
void isShortcut_data();
void isShortcut();
+ void isAlias_data();
+ void isAlias();
+
void link_data();
void link();
void isHidden_data();
void isHidden();
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
void isHiddenFromFinder();
#endif
@@ -285,6 +240,7 @@ private slots:
void nonExistingFile();
void stdfilesystem();
+ void readSymLink();
private:
const QString m_currentDir;
@@ -397,7 +353,7 @@ void tst_QFileInfo::isDir_data()
QFile::remove("brokenlink.lnk");
QFile::remove("dummyfile");
QFile file3("dummyfile");
- file3.open(QIODevice::WriteOnly);
+ QVERIFY(file3.open(QIODevice::WriteOnly));
if (file3.link("brokenlink.lnk")) {
file3.remove();
QFileInfo info3("brokenlink.lnk");
@@ -424,7 +380,7 @@ void tst_QFileInfo::isDir_data()
//QTest::newRow("drive 2") << "t:s" << false;
#endif
#if defined(Q_OS_WIN)
- const QString uncRoot = QStringLiteral("//") + QtNetworkSettings::winServerName();
+ const QString uncRoot = QStringLiteral("//") + QTest::uncServerName();
QTest::newRow("unc 1") << uncRoot << true;
QTest::newRow("unc 2") << uncRoot + QLatin1Char('/') << true;
QTest::newRow("unc 3") << uncRoot + "/testshare" << true;
@@ -467,7 +423,7 @@ void tst_QFileInfo::isRoot_data()
#endif
#if defined(Q_OS_WIN)
- const QString uncRoot = QStringLiteral("//") + QtNetworkSettings::winServerName();
+ const QString uncRoot = QStringLiteral("//") + QTest::uncServerName();
QTest::newRow("unc 1") << uncRoot << true;
QTest::newRow("unc 2") << uncRoot + QLatin1Char('/') << true;
QTest::newRow("unc 3") << uncRoot + "/testshare" << false;
@@ -511,7 +467,7 @@ void tst_QFileInfo::exists_data()
QTest::newRow("simple dir with slash") << (m_resourcesDir + QLatin1Char('/')) << true;
#if defined(Q_OS_WIN)
- const QString uncRoot = QStringLiteral("//") + QtNetworkSettings::winServerName();
+ const QString uncRoot = QStringLiteral("//") + QTest::uncServerName();
QTest::newRow("unc 1") << uncRoot << true;
QTest::newRow("unc 2") << uncRoot + QLatin1Char('/') << true;
QTest::newRow("unc 3") << uncRoot + "/testshare" << true;
@@ -702,7 +658,7 @@ void tst_QFileInfo::canonicalFilePath()
QFile file(QDir::currentPath());
if (file.link(link)) {
QFile tempfile("tempfile.txt");
- tempfile.open(QIODevice::ReadWrite);
+ QVERIFY(tempfile.open(QIODevice::ReadWrite));
tempfile.write("This file is generated by the QFileInfo autotest.");
QVERIFY(tempfile.flush());
tempfile.close();
@@ -740,12 +696,11 @@ void tst_QFileInfo::canonicalFilePath()
#if defined(Q_OS_WIN)
{
- QString errorMessage;
const QString linkTarget = QStringLiteral("res");
- const DWORD dwErr = createSymbolicLink(linkTarget, m_resourcesDir, &errorMessage);
- if (dwErr == ERROR_PRIVILEGE_NOT_HELD)
- QSKIP(msgInsufficientPrivileges(errorMessage));
- QVERIFY2(dwErr == ERROR_SUCCESS, qPrintable(errorMessage));
+ const auto result = FileSystem::createSymbolicLink(linkTarget, m_resourcesDir);
+ if (result.dwErr == ERROR_PRIVILEGE_NOT_HELD)
+ QSKIP(msgInsufficientPrivileges(result.errorMessage));
+ QVERIFY2(result.dwErr == ERROR_SUCCESS, qPrintable(result.errorMessage));
QString currentPath = QDir::currentPath();
QVERIFY(QDir::setCurrent(linkTarget));
const QString actualCanonicalPath = QFileInfo("file1").canonicalFilePath();
@@ -809,7 +764,7 @@ void tst_QFileInfo::bundleName_data()
QTest::newRow("root") << "/" << "";
QTest::newRow("etc") << "/etc" << "";
-#ifdef Q_OS_MAC
+#ifdef Q_OS_DARWIN
QTest::newRow("safari") << "/Applications/Safari.app" << "Safari";
#endif
}
@@ -1040,6 +995,11 @@ void tst_QFileInfo::systemFiles()
QVERIFY(fi.birthTime() <= fi.lastModified());
}
+void tst_QFileInfo::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QFileInfo>();
+}
+
void tst_QFileInfo::compare_data()
{
QTest::addColumn<QString>("file1");
@@ -1066,7 +1026,7 @@ void tst_QFileInfo::compare_data()
<< m_sourceFile
#if defined(Q_OS_WIN)
<< true;
-#elif defined(Q_OS_MAC)
+#elif defined(Q_OS_DARWIN)
<< !pathconf(QDir::currentPath().toLatin1().constData(), _PC_CASE_SENSITIVE);
#else
<< false;
@@ -1075,7 +1035,7 @@ void tst_QFileInfo::compare_data()
void tst_QFileInfo::compare()
{
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
if (qstrcmp(QTest::currentDataTag(), "casesense1") == 0)
QSKIP("Qt thinks all UNIX filesystems are case sensitive, see QTBUG-28246");
#endif
@@ -1084,7 +1044,7 @@ void tst_QFileInfo::compare()
QFETCH(QString, file2);
QFETCH(bool, same);
QFileInfo fi1(file1), fi2(file2);
- QCOMPARE(fi1 == fi2, same);
+ QT_TEST_EQUALITY_OPS(fi1, fi2, same);
}
void tst_QFileInfo::consistent_data()
@@ -1152,8 +1112,8 @@ void tst_QFileInfo::fileTimes()
{
// try to guess if file times on this filesystem round to the second
QFileInfo cwd(".");
- if (cwd.lastModified().toMSecsSinceEpoch() % 1000 == 0
- && cwd.lastRead().toMSecsSinceEpoch() % 1000 == 0) {
+ if (cwd.lastModified(QTimeZone::UTC).toMSecsSinceEpoch() % 1000 == 0
+ && cwd.lastRead(QTimeZone::UTC).toMSecsSinceEpoch() % 1000 == 0) {
fsClockSkew = sleepTime = 1000;
noAccessTime = qIsLikelyToBeFat(fileName);
@@ -1173,46 +1133,46 @@ void tst_QFileInfo::fileTimes()
QDateTime birthTime, writeTime, metadataChangeTime, readTime;
// --- Create file and write to it
- beforeBirth = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
+ beforeBirth = QDateTime::currentDateTimeUtc().addMSecs(-fsClockSkew);
{
QFile file(fileName);
QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
QFileInfo fileInfo(fileName);
- birthTime = fileInfo.birthTime();
+ birthTime = fileInfo.birthTime(QTimeZone::UTC);
QVERIFY2(!birthTime.isValid() || birthTime > beforeBirth,
datePairString(birthTime, beforeBirth));
QTest::qSleep(sleepTime);
- beforeWrite = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
+ beforeWrite = QDateTime::currentDateTimeUtc().addMSecs(-fsClockSkew);
QTextStream ts(&file);
ts << fileName << Qt::endl;
}
{
QFileInfo fileInfo(fileName);
- writeTime = fileInfo.lastModified();
+ writeTime = fileInfo.lastModified(QTimeZone::UTC);
QVERIFY2(writeTime > beforeWrite, datePairString(writeTime, beforeWrite));
- QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
+ QCOMPARE(fileInfo.birthTime(QTimeZone::UTC), birthTime); // mustn't have changed
}
// --- Change the file's metadata
QTest::qSleep(sleepTime);
- beforeMetadataChange = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
+ beforeMetadataChange = QDateTime::currentDateTimeUtc().addMSecs(-fsClockSkew);
{
QFile file(fileName);
file.setPermissions(file.permissions());
}
{
QFileInfo fileInfo(fileName);
- metadataChangeTime = fileInfo.metadataChangeTime();
+ metadataChangeTime = fileInfo.metadataChangeTime(QTimeZone::UTC);
QVERIFY2(metadataChangeTime > beforeMetadataChange,
datePairString(metadataChangeTime, beforeMetadataChange));
QVERIFY(metadataChangeTime >= writeTime); // not all filesystems can store both times
- QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
+ QCOMPARE(fileInfo.birthTime(QTimeZone::UTC), birthTime); // mustn't have changed
}
// --- Read the file
QTest::qSleep(sleepTime);
- beforeRead = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
+ beforeRead = QDateTime::currentDateTimeUtc().addMSecs(-fsClockSkew);
{
QFile file(fileName);
QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
@@ -1222,12 +1182,12 @@ void tst_QFileInfo::fileTimes()
}
QFileInfo fileInfo(fileName);
- readTime = fileInfo.lastRead();
- QCOMPARE(fileInfo.lastModified(), writeTime); // mustn't have changed
- QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
+ readTime = fileInfo.lastRead(QTimeZone::UTC);
+ QCOMPARE(fileInfo.lastModified(QTimeZone::UTC), writeTime); // mustn't have changed
+ QCOMPARE(fileInfo.birthTime(QTimeZone::UTC), birthTime); // mustn't have changed
QVERIFY(readTime.isValid());
-#if defined(Q_OS_QNX) || (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED))
+#if defined(Q_OS_QNX) || defined(Q_OS_ANDROID)
noAccessTime = true;
#elif defined(Q_OS_WIN)
//In Vista the last-access timestamp is not updated when the file is accessed/touched (by default).
@@ -1248,6 +1208,21 @@ void tst_QFileInfo::fileTimes()
QVERIFY(writeTime < beforeRead);
}
+void tst_QFileInfo::setFileTimes()
+{
+ QByteArray data("OLE\nOLE\nOLE");
+ QTemporaryFile file;
+
+ QVERIFY(file.open());
+ QCOMPARE(file.write(data), data.size());
+ QCOMPARE(file.size(), data.size());
+
+ const QDateTime before = QDateTime::currentDateTimeUtc().addMSecs(-5000);
+ QVERIFY(file.setFileTime(before, QFile::FileModificationTime));
+ const QDateTime mtime = file.fileTime(QFile::FileModificationTime).toUTC();
+ QCOMPARE(mtime, before);
+}
+
void tst_QFileInfo::fakeFileTimes_data()
{
QTest::addColumn<QDateTime>("when");
@@ -1265,7 +1240,7 @@ void tst_QFileInfo::fakeFileTimes()
QFETCH(QDateTime, when);
QFile file("faketimefile.txt");
- file.open(QIODevice::WriteOnly);
+ QVERIFY(file.open(QIODevice::WriteOnly));
file.write("\n", 1);
file.close();
@@ -1274,12 +1249,12 @@ void tst_QFileInfo::fakeFileTimes()
the file is open at the time. Of course, when writing, close() changes
modification time, so need to re-open for read in order to setFileTime().
*/
- file.open(QIODevice::ReadOnly);
+ QVERIFY(file.open(QIODevice::ReadOnly));
bool ok = file.setFileTime(when, QFileDevice::FileModificationTime);
file.close();
if (ok)
- QCOMPARE(QFileInfo(file.fileName()).lastModified(), when);
+ QCOMPARE(QFileInfo(file.fileName()).lastModified(QTimeZone::UTC), when);
else
QSKIP("Unable to set file metadata to contrived values");
}
@@ -1296,7 +1271,7 @@ void tst_QFileInfo::isSymLink_data()
QVERIFY(file1.link("link.lnk"));
QFile file2("dummyfile");
- file2.open(QIODevice::WriteOnly);
+ QVERIFY(file2.open(QIODevice::WriteOnly));
QVERIFY(file2.link("brokenlink.lnk"));
file2.remove();
@@ -1371,6 +1346,57 @@ void tst_QFileInfo::isShortcut()
QCOMPARE(fi.isShortcut(), isShortcut);
}
+void tst_QFileInfo::isAlias_data()
+{
+ QFile::remove("symlink");
+ QFile::remove("file-alias");
+ QFile::remove("directory-alias");
+
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<bool>("isAlias");
+
+ QFile regularFile(m_sourceFile);
+ QTest::newRow("regular-file") << regularFile.fileName() << false;
+ QTest::newRow("directory") << QDir::currentPath() << false;
+
+#if defined(Q_OS_MACOS)
+ auto createAlias = [](const QString &target, const QString &alias) {
+ NSURL *targetUrl = [NSURL fileURLWithPath:target.toNSString()];
+ NSURL *aliasUrl = [NSURL fileURLWithPath:alias.toNSString()];
+ NSData *bookmarkData = [targetUrl bookmarkDataWithOptions:NSURLBookmarkCreationSuitableForBookmarkFile
+ includingResourceValuesForKeys:nil relativeToURL:nil error:nullptr];
+ Q_ASSERT(bookmarkData);
+
+ bool success = [NSURL writeBookmarkData:bookmarkData toURL:aliasUrl
+ options:NSURLBookmarkCreationSuitableForBookmarkFile error:nullptr];
+ Q_ASSERT(success);
+ };
+
+ regularFile.link("symlink");
+ QTest::newRow("symlink") << "symlink" << false;
+
+ createAlias(regularFile.fileName(), QDir::current().filePath("file-alias"));
+ QTest::newRow("file-alias") << "file-alias" << true;
+
+ createAlias(QDir::currentPath(), QDir::current().filePath("directory-alias"));
+ QTest::newRow("directory-alias") << "directory-alias" << true;
+
+ regularFile.copy("non-existing-file");
+ createAlias("non-existing-file", QDir::current().filePath("non-existing-file-alias"));
+ QDir::current().remove("non-existing-file");
+ QTest::newRow("non-existing-file-alias") << "non-existing-file-alias" << true;
+#endif
+}
+
+void tst_QFileInfo::isAlias()
+{
+ QFETCH(QString, path);
+ QFETCH(bool, isAlias);
+
+ QFileInfo fi(path);
+ QCOMPARE(fi.isAlias(), isAlias);
+}
+
void tst_QFileInfo::isSymbolicLink_data()
{
QTest::addColumn<QString>("path");
@@ -1384,12 +1410,11 @@ void tst_QFileInfo::isSymbolicLink_data()
#ifndef Q_NO_SYMLINKS
#if defined(Q_OS_WIN)
- QString errorMessage;
- const DWORD creationResult = createSymbolicLink("symlink", m_sourceFile, &errorMessage);
- if (creationResult == ERROR_PRIVILEGE_NOT_HELD) {
- QWARN(msgInsufficientPrivileges(errorMessage));
+ const auto creationResult = FileSystem::createSymbolicLink("symlink", m_sourceFile);
+ if (creationResult.dwErr == ERROR_PRIVILEGE_NOT_HELD) {
+ qWarning() << qPrintable(msgInsufficientPrivileges(creationResult.errorMessage));
} else {
- QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage));
+ QVERIFY2(creationResult.dwErr == ERROR_SUCCESS, qPrintable(creationResult.errorMessage));
QTest::newRow("NTFS-symlink")
<< "symlink" << true;
}
@@ -1432,7 +1457,7 @@ void tst_QFileInfo::link_data()
QFile file1(m_sourceFile);
QFile file2("dummyfile");
- file2.open(QIODevice::WriteOnly);
+ QVERIFY(file2.open(QIODevice::WriteOnly));
QTest::newRow("existent file") << m_sourceFile << false << false << "";
#if defined(Q_OS_WIN)
@@ -1448,21 +1473,20 @@ void tst_QFileInfo::link_data()
#ifndef Q_NO_SYMLINKS
#if defined(Q_OS_WIN)
- QString errorMessage;
- DWORD creationResult = createSymbolicLink("link", m_sourceFile, &errorMessage);
- if (creationResult == ERROR_PRIVILEGE_NOT_HELD) {
- QWARN(msgInsufficientPrivileges(errorMessage));
+ auto creationResult = FileSystem::createSymbolicLink("link", m_sourceFile);
+ if (creationResult.dwErr == ERROR_PRIVILEGE_NOT_HELD) {
+ qWarning() << qPrintable(msgInsufficientPrivileges(creationResult.errorMessage));
} else {
- QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage));
+ QVERIFY2(creationResult.dwErr == ERROR_SUCCESS, qPrintable(creationResult.errorMessage));
QTest::newRow("link")
<< "link" << false << true << QFileInfo(m_sourceFile).absoluteFilePath();
}
- creationResult = createSymbolicLink("brokenlink", "dummyfile", &errorMessage);
- if (creationResult == ERROR_PRIVILEGE_NOT_HELD) {
- QWARN(msgInsufficientPrivileges(errorMessage));
+ creationResult = FileSystem::createSymbolicLink("brokenlink", "dummyfile");
+ if (creationResult.dwErr == ERROR_PRIVILEGE_NOT_HELD) {
+ qWarning() << qPrintable(msgInsufficientPrivileges(creationResult.errorMessage));
} else {
- QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage));
+ QVERIFY2(creationResult.dwErr == ERROR_SUCCESS, qPrintable(creationResult.errorMessage));
QTest::newRow("broken link")
<< "brokenlink" << false << true << QFileInfo("dummyfile").absoluteFilePath();
}
@@ -1501,9 +1525,9 @@ void tst_QFileInfo::isHidden_data()
{
QTest::addColumn<QString>("path");
QTest::addColumn<bool>("isHidden");
- foreach (const QFileInfo& info, QDir::drives()) {
+ const auto drives = QDir::drives();
+ for (const QFileInfo& info : drives)
QTest::newRow(qPrintable("drive." + info.path())) << info.path() << false;
- }
#if defined(Q_OS_WIN)
QVERIFY(QDir("./hidden-directory").exists() || QDir().mkdir("./hidden-directory"));
@@ -1518,14 +1542,14 @@ void tst_QFileInfo::isHidden_data()
QTest::newRow("/path/to/.hidden-directory/..") << QDir::currentPath() + QString("/.hidden-directory/..") << true;
#endif
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
// /bin has the hidden attribute on OS X
QTest::newRow("/bin/") << QString::fromLatin1("/bin/") << true;
#elif !defined(Q_OS_WIN)
QTest::newRow("/bin/") << QString::fromLatin1("/bin/") << false;
#endif
-#ifdef Q_OS_MAC
+#ifdef Q_OS_DARWIN
QTest::newRow("mac_etc") << QString::fromLatin1("/etc") << true;
QTest::newRow("mac_private_etc") << QString::fromLatin1("/private/etc") << false;
QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications") << false;
@@ -1541,7 +1565,7 @@ void tst_QFileInfo::isHidden()
QCOMPARE(fi.isHidden(), isHidden);
}
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
void tst_QFileInfo::isHiddenFromFinder()
{
const char *filename = "test_foobar.txt";
@@ -1567,7 +1591,7 @@ void tst_QFileInfo::isBundle_data()
QTest::addColumn<QString>("path");
QTest::addColumn<bool>("isBundle");
QTest::newRow("root") << QString::fromLatin1("/") << false;
-#ifdef Q_OS_MAC
+#ifdef Q_OS_DARWIN
QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications") << false;
QTest::newRow("mac_Applications") << QString::fromLatin1("/Applications/Safari.app") << true;
#endif
@@ -1621,14 +1645,14 @@ void tst_QFileInfo::refresh()
file.flush();
QFileInfo info(file);
- QDateTime lastModified = info.lastModified();
+ QDateTime lastModified = info.lastModified(QTimeZone::UTC);
QCOMPARE(info.size(), qint64(7));
QTest::qSleep(sleepTime);
QCOMPARE(file.write("JOJOJO"), qint64(6));
file.flush();
- QCOMPARE(info.lastModified(), lastModified);
+ QCOMPARE(info.lastModified(QTimeZone::UTC), lastModified);
QCOMPARE(info.size(), qint64(7));
#if defined(Q_OS_WIN)
@@ -1636,7 +1660,7 @@ void tst_QFileInfo::refresh()
#endif
info.refresh();
QCOMPARE(info.size(), qint64(13));
- QVERIFY(info.lastModified() > lastModified);
+ QVERIFY(info.lastModified(QTimeZone::UTC) > lastModified);
QFileInfo info2 = info;
QCOMPARE(info2.size(), info.size());
@@ -1665,7 +1689,6 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
{
QTest::addColumn<NtfsTestResource>("resource");
QTest::addColumn<QString>("path");
- QTest::addColumn<bool>("isSymLink");
QTest::addColumn<QString>("linkTarget");
QTest::addColumn<QString>("canonicalFilePath");
@@ -1693,13 +1716,13 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
QTest::newRow("absolute dir symlink")
<< NtfsTestResource(NtfsTestResource::SymLink, absSymlink, absTarget)
- << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalPath();
+ << absSymlink << QDir::fromNativeSeparators(absTarget) << target.canonicalPath();
QTest::newRow("relative dir symlink")
<< NtfsTestResource(NtfsTestResource::SymLink, relSymlink, relTarget)
- << relSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalPath();
+ << relSymlink << QDir::fromNativeSeparators(absTarget) << target.canonicalPath();
QTest::newRow("file in symlink dir")
<< NtfsTestResource()
- << fileInSymlink << false << "" << target.canonicalPath().append("/file");
+ << fileInSymlink << "" << target.canonicalPath().append("/file");
}
{
//File symlinks
@@ -1715,23 +1738,22 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
QTest::newRow("absolute file symlink")
<< NtfsTestResource(NtfsTestResource::SymLink, absSymlink, absTarget)
- << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
+ << absSymlink << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
QTest::newRow("relative file symlink")
<< NtfsTestResource(NtfsTestResource::SymLink, relSymlink, relTarget)
- << relSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
+ << relSymlink << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
QTest::newRow("relative to relative file symlink")
<< NtfsTestResource(NtfsTestResource::SymLink, relToRelSymlink, relToRelTarget)
- << relToRelSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
+ << relToRelSymlink << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
}
{
// Symlink to UNC share
pwd.mkdir("unc");
- QString errorMessage;
- QString uncTarget = QStringLiteral("//") + QtNetworkSettings::winServerName() + "/testshare";
+ QString uncTarget = QStringLiteral("//") + QTest::uncServerName() + "/testshare";
QString uncSymlink = QDir::toNativeSeparators(pwd.absolutePath().append("\\unc\\link_to_unc"));
QTest::newRow("UNC symlink")
<< NtfsTestResource(NtfsTestResource::SymLink, uncSymlink, uncTarget)
- << QDir::fromNativeSeparators(uncSymlink) << true << QDir::fromNativeSeparators(uncTarget) << uncTarget;
+ << QDir::fromNativeSeparators(uncSymlink) << QDir::fromNativeSeparators(uncTarget) << uncTarget;
}
//Junctions
@@ -1740,7 +1762,7 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
QFileInfo targetInfo(target);
QTest::newRow("junction_pwd")
<< NtfsTestResource(NtfsTestResource::Junction, junction, target)
- << junction << false << QString() << QString();
+ << junction << QString() << QString();
QFileInfo fileInJunction(targetInfo.absoluteFilePath().append("/file"));
QFile file(fileInJunction.absoluteFilePath());
@@ -1749,14 +1771,14 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
QVERIFY2(file.exists(), msgDoesNotExist(file.fileName()).constData());
QTest::newRow("file in junction")
<< NtfsTestResource()
- << fileInJunction.absoluteFilePath() << false << QString() << fileInJunction.canonicalFilePath();
+ << fileInJunction.absoluteFilePath() << QString() << fileInJunction.canonicalFilePath();
target = QDir::rootPath();
junction = "junction_root";
targetInfo.setFile(target);
QTest::newRow("junction_root")
<< NtfsTestResource(NtfsTestResource::Junction, junction, target)
- << junction << false << QString() << QString();
+ << junction << QString() << QString();
//Mountpoint
wchar_t buffer[MAX_PATH];
@@ -1767,35 +1789,37 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
rootVolume.replace("\\\\?\\","\\??\\");
QTest::newRow("mountpoint")
<< NtfsTestResource(NtfsTestResource::Junction, junction, rootVolume)
- << junction << false << QString() << QString();
+ << junction << QString() << QString();
}
void tst_QFileInfo::ntfsJunctionPointsAndSymlinks()
{
QFETCH(NtfsTestResource, resource);
QFETCH(QString, path);
- QFETCH(bool, isSymLink);
QFETCH(QString, linkTarget);
QFETCH(QString, canonicalFilePath);
- QString errorMessage;
- DWORD creationResult = ERROR_SUCCESS;
+ bool isSymLink = false;
+ bool isJunction = false;
+ FileSystem::Result creationResult;
switch (resource.type) {
case NtfsTestResource::None:
break;
case NtfsTestResource::SymLink:
- creationResult = createSymbolicLink(resource.source, resource.target, &errorMessage);
+ isSymLink = true;
+ creationResult = FileSystem::createSymbolicLink(resource.source, resource.target);
break;
case NtfsTestResource::Junction:
- creationResult = FileSystem::createNtfsJunction(resource.target, resource.source, &errorMessage);
- if (creationResult == ERROR_NOT_SUPPORTED) // Special value indicating non-NTFS drive
- QSKIP(qPrintable(errorMessage));
+ isJunction = true;
+ creationResult = FileSystem::createNtfsJunction(resource.target, resource.source);
+ if (creationResult.dwErr == ERROR_NOT_SUPPORTED) // Special value indicating non-NTFS drive
+ QSKIP(qPrintable(creationResult.errorMessage));
break;
}
- if (creationResult == ERROR_PRIVILEGE_NOT_HELD)
- QSKIP(msgInsufficientPrivileges(errorMessage));
- QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage));
+ if (creationResult.dwErr == ERROR_PRIVILEGE_NOT_HELD)
+ QSKIP(msgInsufficientPrivileges(creationResult.errorMessage));
+ QVERIFY2(creationResult.dwErr == ERROR_SUCCESS, qPrintable(creationResult.errorMessage));
QFileInfo fi(path);
auto guard = qScopeGuard([&fi, this]() {
@@ -1810,14 +1834,36 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks()
}
}
});
- const QString actualSymLinkTarget = isSymLink ? fi.symLinkTarget() : QString();
- const QString actualCanonicalFilePath = isSymLink ? fi.canonicalFilePath() : QString();
- QCOMPARE(fi.isJunction(), resource.type == NtfsTestResource::Junction);
+ const QString actualCanonicalFilePath = fi.canonicalFilePath();
+ QCOMPARE(fi.isJunction(), isJunction);
QCOMPARE(fi.isSymbolicLink(), isSymLink);
if (isSymLink) {
- QCOMPARE(actualSymLinkTarget, linkTarget);
+ QCOMPARE(fi.symLinkTarget(), linkTarget);
QCOMPARE(actualCanonicalFilePath, canonicalFilePath);
}
+
+ if (isJunction) {
+ if (creationResult.target.startsWith(uR"(\??\)"))
+ creationResult.target = creationResult.target.sliced(4);
+
+ // resolve volume to drive letter
+ static const QRegularExpression matchVolumeRe(uR"(^Volume\{([a-z]|[0-9]|-)+\}\\)"_s,
+ QRegularExpression::CaseInsensitiveOption);
+ auto matchVolume = matchVolumeRe.match(creationResult.target);
+ if (matchVolume.hasMatch()) {
+ Q_ASSERT(matchVolume.capturedStart() == 0);
+ DWORD len;
+ wchar_t buffer[MAX_PATH];
+ const QString volumeName = uR"(\\?\)"_s + matchVolume.captured();
+ if (GetVolumePathNamesForVolumeName(reinterpret_cast<LPCWSTR>(volumeName.utf16()),
+ buffer, MAX_PATH, &len) != 0) {
+ creationResult.target.replace(0, matchVolume.capturedLength(),
+ QString::fromWCharArray(buffer));
+ }
+ }
+ QCOMPARE(fi.junctionTarget(), QDir::fromNativeSeparators(creationResult.target));
+ QCOMPARE(actualCanonicalFilePath, QFileInfo(creationResult.link).canonicalFilePath());
+ }
}
void tst_QFileInfo::brokenShortcut()
@@ -1848,7 +1894,7 @@ void tst_QFileInfo::brokenShortcut()
void tst_QFileInfo::isWritable()
{
QFile tempfile("tempfile.txt");
- tempfile.open(QIODevice::WriteOnly);
+ QVERIFY(tempfile.open(QIODevice::WriteOnly));
tempfile.write("This file is generated by the QFileInfo autotest.");
tempfile.close();
@@ -1862,15 +1908,14 @@ void tst_QFileInfo::isWritable()
#endif
#if defined (Q_OS_WIN)
- QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup);
- qt_ntfs_permission_lookup = 1;
+ QNtfsPermissionCheckGuard permissionGuard;
QFileInfo fi2(QFile::decodeName(qgetenv("SystemRoot") + "/system.ini"));
QVERIFY(fi2.exists());
QCOMPARE(fi2.isWritable(), IsUserAdmin());
#endif
#if defined (Q_OS_QNX) // On QNX /etc is usually on a read-only filesystem
- QVERIFY(!QFileInfo("/etc/passwd").isWritable());
+ QCOMPARE(QFileInfo("/etc/passwd").isWritable(), (geteuid() == 0));
#elif defined (Q_OS_UNIX) && !defined(Q_OS_VXWORKS) // VxWorks does not have users/groups
for (const char *attempt : { "/etc/passwd", "/etc/machine-id", "/proc/version" }) {
if (access(attempt, F_OK) == -1)
@@ -1883,8 +1928,14 @@ void tst_QFileInfo::isWritable()
void tst_QFileInfo::isExecutable()
{
QString appPath = QCoreApplication::applicationDirPath();
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
- appPath += "/libtst_qfileinfo.so";
+#ifdef Q_OS_ANDROID
+ QDir dir(appPath);
+ QVERIFY(dir.exists());
+ dir.setNameFilters({ "libtst_qfileinfo*.so" });
+ QStringList entries = dir.entryList();
+ QCOMPARE(entries.size(), 1);
+
+ appPath += "/" + entries[0];
#else
appPath += "/tst_qfileinfo";
# if defined(Q_OS_WIN)
@@ -1892,6 +1943,7 @@ void tst_QFileInfo::isExecutable()
# endif
#endif
QFileInfo fi(appPath);
+ QVERIFY(fi.exists());
QCOMPARE(fi.isExecutable(), true);
QCOMPARE(QFileInfo(m_proFile).isExecutable(), false);
@@ -1962,7 +2014,7 @@ private:
void tst_QFileInfo::testDecomposedUnicodeNames()
{
-#ifndef Q_OS_MAC
+#ifndef Q_OS_DARWIN
QSKIP("This is a OS X only test (unless you know more about filesystems, then maybe you should try it ;)");
#else
QFETCH(QString, filePath);
@@ -2069,7 +2121,7 @@ bool IsUserAdmin()
void tst_QFileInfo::owner()
{
QString userName;
-#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) && !defined(Q_OS_INTEGRITY)
{
passwd *user = getpwuid(geteuid());
QVERIFY(user);
@@ -2106,7 +2158,7 @@ void tst_QFileInfo::owner()
NetApiBufferFree(pBuf);
}
}
- qt_ntfs_permission_lookup = 1;
+ QNtfsPermissionCheckGuard permissionGuard;
#endif
if (userName.isEmpty())
QSKIP("Can't retrieve the user name");
@@ -2123,15 +2175,12 @@ void tst_QFileInfo::owner()
QCOMPARE(fi.owner(), userName);
QFile::remove(fileName);
-#if defined(Q_OS_WIN)
- qt_ntfs_permission_lookup = 0;
-#endif
}
void tst_QFileInfo::group()
{
QString expected;
-#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) && !defined(Q_OS_INTEGRITY)
struct group *gr;
gid_t gid = getegid();
@@ -2209,10 +2258,10 @@ static void stateCheck(const QFileInfo &info, const QString &dirname, const QStr
QCOMPARE(info.permissions(), QFile::Permissions());
- QVERIFY(!info.birthTime().isValid());
- QVERIFY(!info.metadataChangeTime().isValid());
- QVERIFY(!info.lastRead().isValid());
- QVERIFY(!info.lastModified().isValid());
+ QVERIFY(!info.birthTime(QTimeZone::UTC).isValid());
+ QVERIFY(!info.metadataChangeTime(QTimeZone::UTC).isValid());
+ QVERIFY(!info.lastRead(QTimeZone::UTC).isValid());
+ QVERIFY(!info.lastModified(QTimeZone::UTC).isValid());
};
void tst_QFileInfo::invalidState_data()
@@ -2261,13 +2310,15 @@ void tst_QFileInfo::stdfilesystem()
// We compare using absoluteFilePath since QFileInfo::operator== ends up using
// canonicalFilePath which evaluates to empty-string for non-existent paths causing
// these tests to always succeed.
-#define COMPARE_CONSTRUCTION(filepath) \
- QCOMPARE(QFileInfo(fs::path(filepath)).absoluteFilePath(), \
- QFileInfo(QString::fromLocal8Bit(filepath)).absoluteFilePath()); \
- QCOMPARE(QFileInfo(base, fs::path(filepath)).absoluteFilePath(), \
- QFileInfo(base, QString::fromLocal8Bit(filepath)).absoluteFilePath())
-
QDir base{ "../" }; // Used for the QFileInfo(QDir, <path>) ctor
+ auto doCompare = [&base](const char *filepath) {
+ QCOMPARE(QFileInfo(fs::path(filepath)).absoluteFilePath(),
+ QFileInfo(QString::fromLocal8Bit(filepath)).absoluteFilePath());
+ QCOMPARE(QFileInfo(base, fs::path(filepath)).absoluteFilePath(),
+ QFileInfo(base, QString::fromLocal8Bit(filepath)).absoluteFilePath());
+ };
+#define COMPARE_CONSTRUCTION(filepath) \
+ doCompare(filepath); if (QTest::currentTestFailed()) return
COMPARE_CONSTRUCTION("./file");
@@ -2280,7 +2331,22 @@ void tst_QFileInfo::stdfilesystem()
COMPARE_CONSTRUCTION("/path/TO/file.txt");
COMPARE_CONSTRUCTION("./path/TO/file.txt");
COMPARE_CONSTRUCTION("../file.txt");
+#if !(defined(__GLIBCXX__) && defined(Q_OS_WIN32))
+ // libstdc++ bug on Windows - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111244
COMPARE_CONSTRUCTION("./filæ.txt");
+#endif
+
+ // Test unicode strings
+ QCOMPARE(QFileInfo(fs::path(u"./filæ.txt")).absoluteFilePath(),
+ QFileInfo(u"./filæ.txt"_s).absoluteFilePath());
+ QCOMPARE(QFileInfo(base, fs::path(u"./filæ.txt")).absoluteFilePath(),
+ QFileInfo(base, u"./filæ.txt"_s).absoluteFilePath());
+#ifdef __cpp_char8_t
+ QCOMPARE(QFileInfo(fs::path(u8"./filæ.txt")).absoluteFilePath(),
+ QFileInfo(u8"./filæ.txt").absoluteFilePath());
+ QCOMPARE(QFileInfo(base, fs::path(u8"./filæ.txt")).absoluteFilePath(),
+ QFileInfo(base, u8"./filæ.txt").absoluteFilePath());
+#endif
#undef COMPARE_CONSTRUCTION
{
@@ -2342,5 +2408,20 @@ void tst_QFileInfo::stdfilesystem()
#endif
}
+void tst_QFileInfo::readSymLink()
+{
+ QString symLinkName("./a.link");
+ const auto tidier = qScopeGuard([symLinkName]() { QFile::remove(symLinkName); });
+
+#ifdef Q_OS_WIN
+ QVERIFY2(CreateSymbolicLink(L"a.link", L"..\\..\\a", SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
+ != 0,
+ "Failed to create symlink for test");
+#else
+ QVERIFY2(QFile::link("../../a", symLinkName), "Failed to create symlink for test");
+#endif
+ QFileInfo info(symLinkName);
+ QCOMPARE(info.readSymLink(), QString("../../a"));
+}
QTEST_MAIN(tst_QFileInfo)
#include "tst_qfileinfo.moc"