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.cpp410
1 files changed, 216 insertions, 194 deletions
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index f35dab2cad..8945daff4a 100644
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -35,6 +35,7 @@
#include <qtemporarydir.h>
#include <qdir.h>
#include <qfileinfo.h>
+#include <qstorageinfo.h>
#ifdef Q_OS_UNIX
#include <errno.h>
#include <fcntl.h>
@@ -64,84 +65,38 @@
#define Q_NO_SYMLINKS
#endif
-
-#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
-inline bool qt_isEvilFsTypeName(const char *name)
-{
- return (qstrncmp(name, "nfs", 3) == 0
- || qstrncmp(name, "autofs", 6) == 0
- || qstrncmp(name, "cachefs", 7) == 0);
-}
-
-#if defined(Q_OS_BSD4) && !defined(Q_OS_NETBSD)
-# include <sys/param.h>
-# include <sys/mount.h>
-
-bool qIsLikelyToBeNfs(int handle)
-{
- struct statfs buf;
- if (fstatfs(handle, &buf) != 0)
- return false;
- return qt_isEvilFsTypeName(buf.f_fstypename);
-}
-
-#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
-
-# include <sys/vfs.h>
-# ifdef QT_LINUXBASE
- // LSB 3.2 has fstatfs in sys/statfs.h, sys/vfs.h is just an empty dummy header
-# include <sys/statfs.h>
-# endif
-
-# ifndef NFS_SUPER_MAGIC
-# define NFS_SUPER_MAGIC 0x00006969
-# endif
-# ifndef AUTOFS_SUPER_MAGIC
-# define AUTOFS_SUPER_MAGIC 0x00000187
-# endif
-# ifndef AUTOFSNG_SUPER_MAGIC
-# define AUTOFSNG_SUPER_MAGIC 0x7d92b1a0
-# endif
-
-bool qIsLikelyToBeNfs(int handle)
+inline bool qIsLikelyToBeFat(const QString &path)
{
- struct statfs buf;
- if (fstatfs(handle, &buf) != 0)
- return false;
- return buf.f_type == NFS_SUPER_MAGIC
- || buf.f_type == AUTOFS_SUPER_MAGIC
- || buf.f_type == AUTOFSNG_SUPER_MAGIC;
+ QByteArray name = QStorageInfo(path).fileSystemType().toLower();
+ return name.contains("fat") || name.contains("msdos");
}
-#elif defined(Q_OS_SOLARIS) || defined(Q_OS_IRIX) || defined(Q_OS_AIX) || defined(Q_OS_HPUX) \
- || defined(Q_OS_OSF) || defined(Q_OS_QNX) || defined(Q_OS_SCO) \
- || defined(Q_OS_UNIXWARE) || defined(Q_OS_RELIANT) || defined(Q_OS_NETBSD)
-
-# include <sys/statvfs.h>
-
-bool qIsLikelyToBeNfs(int handle)
+inline bool qIsLikelyToBeNfs(const QString &path)
{
- struct statvfs buf;
- if (fstatvfs(handle, &buf) != 0)
- return false;
-#if defined(Q_OS_NETBSD)
- return qt_isEvilFsTypeName(buf.f_fstypename);
+#ifdef Q_OS_WIN
+ Q_UNUSED(path);
+ return false;
#else
- return qt_isEvilFsTypeName(buf.f_basetype);
+ QByteArray type = QStorageInfo(path).fileSystemType();
+ const char *name = type.constData();
+
+ return (qstrncmp(name, "nfs", 3) == 0
+ || qstrncmp(name, "autofs", 6) == 0
+ || qstrncmp(name, "autofsng", 8) == 0
+ || qstrncmp(name, "cachefs", 7) == 0);
#endif
}
-#else
-inline bool qIsLikelyToBeNfs(int /* handle */)
-{
- return false;
-}
-#endif
-#endif
static QString seedAndTemplate()
{
- qsrand(QDateTime::currentSecsSinceEpoch());
- return QDir::tempPath() + "/tst_qfileinfo-XXXXXX";
+ QString base;
+#if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID)
+ // use XDG_RUNTIME_DIR as it's a fully-capable FS
+ base = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
+#endif
+ if (base.isEmpty())
+ base = QDir::tempPath();
+ return base + "/tst_qfileinfo-XXXXXX";
}
static QByteArray msgDoesNotExist(const QString &name)
@@ -277,8 +232,9 @@ private slots:
#endif
void group();
+ void invalidState_data();
void invalidState();
- void nonExistingFileDates();
+ void nonExistingFile();
private:
const QString m_currentDir;
@@ -1034,6 +990,11 @@ void tst_QFileInfo::systemFiles()
QVERIFY2(fi.exists(), msgDoesNotExist(fi.absoluteFilePath()).constData());
QVERIFY(fi.size() > 0);
QVERIFY(fi.lastModified().isValid());
+ QVERIFY(fi.metadataChangeTime().isValid());
+ QCOMPARE(fi.metadataChangeTime(), fi.lastModified()); // On Windows, they're the same
+ QVERIFY(fi.birthTime().isValid());
+ QVERIFY(fi.birthTime() <= fi.lastModified());
+ QCOMPARE(fi.created(), fi.birthTime()); // On Windows, they're the same
}
void tst_QFileInfo::compare_data()
@@ -1124,43 +1085,92 @@ void tst_QFileInfo::fileTimes_data()
void tst_QFileInfo::fileTimes()
{
- int sleepTime = 2000;
+ auto datePairString = [](const QDateTime &actual, const QDateTime &before) {
+ return (actual.toString(Qt::ISODateWithMs) + " (should be >) " + before.toString(Qt::ISODateWithMs))
+ .toLatin1();
+ };
+
QFETCH(QString, fileName);
+ int sleepTime = 100;
+
+ // on Linux and Windows, the filesystem timestamps may be slightly out of
+ // sync with the system clock (maybe they're using CLOCK_REALTIME_COARSE),
+ // so add a margin of error to our comparisons
+ int fsClockSkew = 10;
+#ifdef Q_OS_WIN
+ fsClockSkew = 500;
+#endif
+
+ // NFS clocks may be WAY out of sync
+ if (qIsLikelyToBeNfs(fileName))
+ QSKIP("This test doesn't work on NFS");
+
+ bool noAccessTime = false;
+ {
+ // 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) {
+ fsClockSkew = sleepTime = 1000;
+
+ noAccessTime = qIsLikelyToBeFat(fileName);
+ if (noAccessTime) {
+ // FAT filesystems (but maybe not exFAT) store timestamps with 2-second
+ // granularity and access time with 1-day granularity
+ fsClockSkew = sleepTime = 2000;
+ }
+ }
+ }
+
if (QFile::exists(fileName)) {
QVERIFY(QFile::remove(fileName));
}
- QTest::qSleep(sleepTime);
+
+ QDateTime beforeBirth, beforeWrite, beforeMetadataChange, beforeRead;
+ QDateTime birthTime, writeTime, metadataChangeTime, readTime;
+
+ // --- Create file and write to it
+ beforeBirth = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
{
QFile file(fileName);
QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
-#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS)
- if (qIsLikelyToBeNfs(file.handle()))
- QSKIP("This Test doesn't work on NFS");
-#endif
+ QFileInfo fileInfo(fileName);
+ birthTime = fileInfo.birthTime();
+ QVERIFY2(!birthTime.isValid() || birthTime > beforeBirth,
+ datePairString(birthTime, beforeBirth));
+
+ QTest::qSleep(sleepTime);
+ beforeWrite = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
QTextStream ts(&file);
ts << fileName << endl;
}
- QTest::qSleep(sleepTime);
- QDateTime beforeWrite = QDateTime::currentDateTime();
- QTest::qSleep(sleepTime);
{
QFileInfo fileInfo(fileName);
- QVERIFY(fileInfo.created() < beforeWrite);
- QFile file(fileName);
- QVERIFY(file.open(QFile::ReadWrite | QFile::Text));
- QTextStream ts(&file);
- ts << fileName << endl;
+ writeTime = fileInfo.lastModified();
+ QVERIFY2(writeTime > beforeWrite, datePairString(writeTime, beforeWrite));
+ QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
}
+
+ // --- Change the file's metadata
QTest::qSleep(sleepTime);
- QDateTime beforeRead = QDateTime::currentDateTime();
- QTest::qSleep(sleepTime);
+ beforeMetadataChange = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
+ {
+ QFile file(fileName);
+ file.setPermissions(file.permissions());
+ }
{
QFileInfo fileInfo(fileName);
-// On unix created() returns the same as lastModified().
-#if !defined(Q_OS_UNIX)
- QVERIFY(fileInfo.created() < beforeWrite);
-#endif
- QVERIFY(fileInfo.lastModified() > beforeWrite);
+ metadataChangeTime = fileInfo.metadataChangeTime();
+ QVERIFY2(metadataChangeTime > beforeMetadataChange,
+ datePairString(metadataChangeTime, beforeMetadataChange));
+ QVERIFY(metadataChangeTime >= writeTime); // not all filesystems can store both times
+ QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
+ }
+
+ // --- Read the file
+ QTest::qSleep(sleepTime);
+ beforeRead = QDateTime::currentDateTime().addMSecs(-fsClockSkew);
+ {
QFile file(fileName);
QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
QTextStream ts(&file);
@@ -1169,13 +1179,17 @@ void tst_QFileInfo::fileTimes()
}
QFileInfo fileInfo(fileName);
-#if !defined(Q_OS_UNIX)
- QVERIFY(fileInfo.created() < beforeWrite);
-#endif
+ readTime = fileInfo.lastRead();
+ QCOMPARE(fileInfo.lastModified(), writeTime); // mustn't have changed
+ QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
+ QVERIFY(readTime.isValid());
+
+#if defined(Q_OS_WINRT) || 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).
//To enable this the HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate
//is set to 0, in the test machine.
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
HKEY key;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\FileSystem",
0, KEY_READ, &key)) {
@@ -1184,75 +1198,43 @@ void tst_QFileInfo::fileTimes()
LONG error = RegQueryValueEx(key, L"NtfsDisableLastAccessUpdate"
, NULL, NULL, (LPBYTE)&disabledAccessTimes, &size);
if (ERROR_SUCCESS == error && disabledAccessTimes)
- QEXPECT_FAIL("", "File access times are disabled in windows registry (this is the default setting)", Continue);
+ noAccessTime = true;
RegCloseKey(key);
}
#endif
-#if defined(Q_OS_WINRT)
- QEXPECT_FAIL("", "WinRT does not allow timestamp handling change in the filesystem due to sandboxing", Continue);
-#elif defined(Q_OS_QNX)
- QEXPECT_FAIL("", "QNX uses the noatime filesystem option", Continue);
-#elif defined(Q_OS_ANDROID)
- if (fileInfo.lastRead() <= beforeRead)
- QEXPECT_FAIL("", "Android may use relatime or noatime on mounts", Continue);
-#endif
- QVERIFY(fileInfo.lastRead() > beforeRead);
- QVERIFY(fileInfo.lastModified() > beforeWrite);
- QVERIFY(fileInfo.lastModified() < beforeRead);
+ if (noAccessTime)
+ return;
+
+ QVERIFY2(readTime > beforeRead, datePairString(readTime, beforeRead));
+ QVERIFY(writeTime < beforeRead);
}
void tst_QFileInfo::fileTimes_oldFile()
{
- // This is not supported on WinRT
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
- // All files are opened in share mode (both read and write).
- DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-
- // All files on Windows can be read; there's no such thing as an
- // unreadable file. Add GENERIC_WRITE if WriteOnly is passed.
- int accessRights = GENERIC_READ | GENERIC_WRITE;
-
- SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
-
- // Regular file mode. In Unbuffered mode, pass the no-buffering flag.
- DWORD flagsAndAtts = FILE_ATTRIBUTE_NORMAL;
-
- // WriteOnly can create files, ReadOnly cannot.
- DWORD creationDisp = OPEN_ALWAYS;
-
- // Create the file handle.
- HANDLE fileHandle = CreateFile(L"oldfile.txt",
- accessRights,
- shareMode,
- &securityAtts,
- creationDisp,
- flagsAndAtts,
- NULL);
-
- // Set file times back to 1601.
- SYSTEMTIME stime;
- stime.wYear = 1601;
- stime.wMonth = 1;
- stime.wDayOfWeek = 1;
- stime.wDay = 1;
- stime.wHour = 1;
- stime.wMinute = 0;
- stime.wSecond = 0;
- stime.wMilliseconds = 0;
-
- FILETIME ctime;
- QVERIFY(SystemTimeToFileTime(&stime, &ctime));
- FILETIME atime = ctime;
- FILETIME mtime = atime;
- QVERIFY(fileHandle);
- QVERIFY(SetFileTime(fileHandle, &ctime, &atime, &mtime) != 0);
-
- CloseHandle(fileHandle);
-
- QFileInfo info("oldfile.txt");
- QCOMPARE(info.lastModified(), QDateTime(QDate(1601, 1, 1), QTime(1, 0), Qt::UTC).toLocalTime());
-#endif
+ // This is 2^{31} seconds before 1970-01-01 15:14:8,
+ // i.e. shortly after the start of time_t, in any time-zone:
+ const QDateTime early(QDate(1901, 12, 14), QTime(12, 0));
+ QFile file("ancientfile.txt");
+ file.open(QIODevice::WriteOnly);
+ file.write("\n", 1);
+ file.close();
+
+ /*
+ QFile's setFileTime calls QFSFileEngine::setFileTime() which fails unless
+ 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);
+ bool ok = file.setFileTime(early, QFileDevice::FileModificationTime);
+ file.close();
+
+ if (ok) {
+ QFileInfo info(file.fileName());
+ QCOMPARE(info.lastModified(), early);
+ } else {
+ QSKIP("Unable to set file metadata to ancient values");
+ }
}
void tst_QFileInfo::isSymLink_data()
@@ -1392,7 +1374,7 @@ void tst_QFileInfo::isNativePath_data()
QTest::addColumn<bool>("isNativePath");
QTest::newRow("default-constructed") << QString() << false;
- QTest::newRow("empty") << QString("") << true;
+ QTest::newRow("empty") << QString("") << false;
QTest::newRow("local root") << QString::fromLatin1("/") << true;
QTest::newRow("local non-existent file") << QString::fromLatin1("/abrakadabra.boo") << true;
@@ -1928,56 +1910,96 @@ void tst_QFileInfo::group()
QCOMPARE(fi.group(), expected);
}
-void tst_QFileInfo::invalidState()
+static void stateCheck(const QFileInfo &info, const QString &dirname, const QString &filename)
{
- // Shouldn't crash;
-
- {
- QFileInfo info;
- QCOMPARE(info.size(), qint64(0));
- QVERIFY(!info.exists());
-
- info.setCaching(false);
+ QCOMPARE(info.size(), qint64(0));
+ QVERIFY(!info.exists());
- info.created();
- info.lastRead();
- info.lastModified();
+ QString path;
+ QString abspath;
+ if (!dirname.isEmpty()) {
+ path = ".";
+ abspath = dirname + '/' + filename;
}
- {
- QFileInfo info("");
- QCOMPARE(info.size(), qint64(0));
- QVERIFY(!info.exists());
-
- info.setCaching(false);
+ QCOMPARE(info.filePath(), filename);
+ QCOMPARE(info.absoluteFilePath(), abspath);
+ QCOMPARE(info.canonicalFilePath(), QString());
+ QCOMPARE(info.fileName(), filename);
+ QCOMPARE(info.baseName(), filename);
+ QCOMPARE(info.completeBaseName(), filename);
+ QCOMPARE(info.suffix(), QString());
+ QCOMPARE(info.bundleName(), QString());
+ QCOMPARE(info.completeSuffix(), QString());
+
+ QVERIFY(info.isRelative());
+ QCOMPARE(info.path(), path);
+ QCOMPARE(info.absolutePath(), dirname);
+ QCOMPARE(info.dir().path(), ".");
+
+ // these don't look right
+ QCOMPARE(info.canonicalPath(), path);
+ QCOMPARE(info.absoluteDir().path(), dirname.isEmpty() ? "." : dirname);
+
+ QVERIFY(!info.isReadable());
+ QVERIFY(!info.isWritable());
+ QVERIFY(!info.isExecutable());
+ QVERIFY(!info.isHidden());
+ QVERIFY(!info.isFile());
+ QVERIFY(!info.isDir());
+ QVERIFY(!info.isSymLink());
+ QVERIFY(!info.isBundle());
+ QVERIFY(!info.isRoot());
+ QCOMPARE(info.isNativePath(), !filename.isEmpty());
+
+ QCOMPARE(info.readLink(), QString());
+ QCOMPARE(info.ownerId(), uint(-2));
+ QCOMPARE(info.groupId(), uint(-2));
+ QCOMPARE(info.owner(), QString());
+ QCOMPARE(info.group(), QString());
+
+ QCOMPARE(info.permissions(), QFile::Permissions());
- info.created();
- info.lastRead();
- info.lastModified();
- }
+ QVERIFY(!info.created().isValid());
+ QVERIFY(!info.birthTime().isValid());
+ QVERIFY(!info.metadataChangeTime().isValid());
+ QVERIFY(!info.lastRead().isValid());
+ QVERIFY(!info.lastModified().isValid());
+};
- {
- QFileInfo info("file-doesn't-really-exist.txt");
- QCOMPARE(info.size(), qint64(0));
- QVERIFY(!info.exists());
+void tst_QFileInfo::invalidState_data()
+{
+ QTest::addColumn<int>("mode");
+ QTest::newRow("default") << 0;
+ QTest::newRow("empty") << 1;
+ QTest::newRow("copy-of-default") << 2;
+ QTest::newRow("copy-of-empty") << 3;
+}
- info.setCaching(false);
+void tst_QFileInfo::invalidState()
+{
+ // Shouldn't crash or produce warnings
+ QFETCH(int, mode);
+ const QFileInfo &info = (mode & 1 ? QFileInfo("") : QFileInfo());
- info.created();
- info.lastRead();
- info.lastModified();
+ if (mode & 2) {
+ QFileInfo copy(info);
+ stateCheck(copy, QString(), QString());
+ } else {
+ stateCheck(info, QString(), QString());
}
-
- QVERIFY(true);
}
-void tst_QFileInfo::nonExistingFileDates()
+void tst_QFileInfo::nonExistingFile()
{
- QFileInfo info("non-existing-file.foobar");
- QVERIFY(!info.exists());
- QVERIFY(!info.created().isValid());
- QVERIFY(!info.lastRead().isValid());
- QVERIFY(!info.lastModified().isValid());
+ QString dirname = QDir::currentPath();
+ QString cdirname = QFileInfo(dirname).canonicalFilePath();
+ if (dirname != cdirname)
+ QDir::setCurrent(cdirname); // chdir() to our canonical path
+
+ QString filename = "non-existing-file-foobar";
+ QFileInfo info(filename);
+ stateCheck(info, dirname, filename);
}
QTEST_MAIN(tst_QFileInfo)