diff options
Diffstat (limited to 'tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp')
-rw-r--r-- | tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp | 261 |
1 files changed, 204 insertions, 57 deletions
diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp index cba7dfe9fc..16b4fb4423 100644 --- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp +++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2020 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -26,13 +27,13 @@ ** ****************************************************************************/ -#include <QtTest/QtTest> #include <qstandardpaths.h> +#include <QtTest/QtTest> #include <qdebug.h> -#include <qstandardpaths.h> #include <qfileinfo.h> -#include <qsysinfo.h> +#include <qplatformdefs.h> #include <qregularexpression.h> +#include <qsysinfo.h> #if defined(Q_OS_WIN) # include <qt_windows.h> #endif @@ -40,14 +41,13 @@ #ifdef Q_OS_UNIX #include <unistd.h> #include <sys/types.h> +#include <pwd.h> #endif #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID) #define Q_XDG_PLATFORM #endif -#include "emulationdetector.h" - // Update this when adding new enum values; update enumNames too static const int MaxStandardLocation = QStandardPaths::AppConfigLocation; @@ -68,6 +68,7 @@ private slots: void testFindExecutable(); void testFindExecutableLinkToDirectory(); void testRuntimeDirectory(); + void testCustomRuntimeDirectory_data(); void testCustomRuntimeDirectory(); void testAllWritableLocations_data(); void testAllWritableLocations(); @@ -455,6 +456,9 @@ void tst_qstandardpaths::testFindExecutableLinkToDirectory() QFile::remove(target); } +using RuntimeDirSetup = QString (*)(QDir &); +Q_DECLARE_METATYPE(RuntimeDirSetup); + void tst_qstandardpaths::testRuntimeDirectory() { #ifdef Q_XDG_PLATFORM @@ -463,6 +467,174 @@ void tst_qstandardpaths::testRuntimeDirectory() #endif } +#ifdef Q_XDG_PLATFORM +static QString fallbackXdgRuntimeDir() +{ + static QString username = [] { + struct passwd *pw = getpwuid(geteuid()); + return QString::fromLocal8Bit(pw->pw_name); + }(); + + // QDir::temp() might change from call to call + return QDir::temp().filePath("runtime-" + username); +} +#endif + +static QString updateRuntimeDir(const QString &path) +{ + qputenv("XDG_RUNTIME_DIR", QFile::encodeName(path)); + return path; +} + +static void clearRuntimeDir() +{ + qunsetenv("XDG_RUNTIME_DIR"); +#ifdef Q_XDG_PLATFORM +#ifndef Q_OS_WASM + QTest::ignoreMessage(QtWarningMsg, + qPrintable("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '" + + fallbackXdgRuntimeDir() + '\'')); +#endif +#endif +} + +void tst_qstandardpaths::testCustomRuntimeDirectory_data() +{ +#if defined(Q_XDG_PLATFORM) + QTest::addColumn<RuntimeDirSetup>("setup"); + auto addRow = [](const char *name, RuntimeDirSetup f) { + QTest::newRow(name) << f; + }; + + +# if defined(Q_OS_UNIX) + if (::getuid() == 0) + QSKIP("Running this test as root doesn't make sense"); +# endif + + addRow("environment:non-existing", [](QDir &d) { + return updateRuntimeDir(d.filePath("runtime")); + }); + + addRow("environment:existing", [](QDir &d) { + QString p = d.filePath("runtime"); + d.mkdir("runtime"); + QFile::setPermissions(p, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + return updateRuntimeDir(p); + }); + + addRow("environment-to-existing-wrong-perm", [](QDir &d) { + QString p = d.filePath("runtime"); + d.mkdir("runtime"); + QFile::setPermissions(p, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | + QFile::ExeGroup | QFile::ExeOther); + return updateRuntimeDir(p); + }); + + addRow("environment:wrong-owner", [](QDir &) { + QT_STATBUF st; + QT_STAT("/", &st); + + updateRuntimeDir("/"); + QTest::ignoreMessage(QtWarningMsg, + QString("QStandardPaths: runtime directory '/' is not owned by UID " + "%1, but a directory permissions %2 owned by UID %3 GID %4") + .arg(getuid()) + .arg(st.st_mode & 07777, 4, 8, QChar('0')) + .arg(st.st_uid) + .arg(st.st_gid).toLatin1()); + return fallbackXdgRuntimeDir(); + }); + + addRow("environment:file", [](QDir &d) { + QString p = d.filePath("file"); + QFile f(p); + f.open(QIODevice::WriteOnly); + f.setPermissions(QFile::ReadOwner | QFile::WriteOwner); + + updateRuntimeDir(p); + QTest::ignoreMessage(QtWarningMsg, + QString("QStandardPaths: runtime directory '%1' is not a directory, " + "but a regular file permissions 0600 owned by UID %2 GID %3") + .arg(p).arg(getuid()).arg(getgid()).toLatin1()); + return fallbackXdgRuntimeDir(); + }); + + addRow("environment:broken-symlink", [](QDir &d) { + QString p = d.filePath("link"); + QFile::link(d.filePath("this-goes-nowhere"), p); + updateRuntimeDir(p); + QTest::ignoreMessage(QtWarningMsg, + QString("QStandardPaths: runtime directory '%1' is not a directory, " + "but a broken symlink") + .arg(p).toLatin1()); + return fallbackXdgRuntimeDir(); + }); + + addRow("environment:symlink-to-dir", [](QDir &d) { + QString p = d.filePath("link"); + d.mkdir("dir"); + QFile::link(d.filePath("dir"), p); + QFile::setPermissions(p, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); + updateRuntimeDir(p); + QTest::ignoreMessage(QtWarningMsg, + QString("QStandardPaths: runtime directory '%1' is not a directory, " + "but a symbolic link to a directory permissions 0700 owned by UID %2 GID %3") + .arg(p).arg(getuid()).arg(getgid()).toLatin1()); + return fallbackXdgRuntimeDir(); + }); + + addRow("no-environment:non-existing", [](QDir &) { + clearRuntimeDir(); + return fallbackXdgRuntimeDir(); + }); + + addRow("no-environment:existing", [](QDir &d) { + clearRuntimeDir(); + QString p = fallbackXdgRuntimeDir(); + d.mkdir(p); // probably has wrong permissions + return p; + }); + + addRow("no-environment:fallback-is-file", [](QDir &) { + QString p = fallbackXdgRuntimeDir(); + QFile f(p); + f.open(QIODevice::WriteOnly); + f.setPermissions(QFile::ReadOwner | QFile::WriteOwner); + + clearRuntimeDir(); + QTest::ignoreMessage(QtWarningMsg, + QString("QStandardPaths: runtime directory '%1' is not a directory, " + "but a regular file permissions 0600 owned by UID %2 GID %3") + .arg(p).arg(getuid()).arg(getgid()).toLatin1()); + return QString(); + }); + + addRow("environment-and-fallback-are-files", [](QDir &d) { + QString p = d.filePath("file1"); + QFile f(p); + f.open(QIODevice::WriteOnly); + f.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup); + updateRuntimeDir(p); + QTest::ignoreMessage(QtWarningMsg, + QString("QStandardPaths: runtime directory '%1' is not a directory, " + "but a regular file permissions 0640 owned by UID %2 GID %3") + .arg(p).arg(getuid()).arg(getgid()).toLatin1()); + + f.close(); + f.setFileName(fallbackXdgRuntimeDir()); + f.open(QIODevice::WriteOnly); + f.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup); + QTest::ignoreMessage(QtWarningMsg, + QString("QStandardPaths: runtime directory '%1' is not a directory, " + "but a regular file permissions 0640 owned by UID %2 GID %3") + .arg(f.fileName()).arg(getuid()).arg(getgid()).toLatin1()); + + return QString(); + }); +#endif +} + void tst_qstandardpaths::testCustomRuntimeDirectory() { #if defined(Q_OS_UNIX) @@ -473,63 +645,38 @@ void tst_qstandardpaths::testCustomRuntimeDirectory() #ifdef Q_XDG_PLATFORM struct EnvVarRestorer { - EnvVarRestorer() : origRuntimeDir(qgetenv("XDG_RUNTIME_DIR")) {} - ~EnvVarRestorer() { qputenv("XDG_RUNTIME_DIR", origRuntimeDir.constData()); } - const QByteArray origRuntimeDir; + ~EnvVarRestorer() + { + qputenv("XDG_RUNTIME_DIR", origRuntimeDir); + qputenv("TMPDIR", origTempDir); + } + const QByteArray origRuntimeDir = qgetenv("XDG_RUNTIME_DIR"); + const QByteArray origTempDir = qgetenv("TMPDIR"); }; EnvVarRestorer restorer; - // When $XDG_RUNTIME_DIR points to a directory with wrong ownership, QStandardPaths should warn - QByteArray rootOwnedFileName = "/tmp"; - if (EmulationDetector::isRunningArmOnX86()) { - // Directory "tmp" under toolchain sysroot is detected by qemu and has same uid as current user. - // Try /opt instead, it might not be located in the sysroot. - QFileInfo rootOwnedFile = QFileInfo(QString::fromLatin1(rootOwnedFileName)); - if (rootOwnedFile.ownerId() == ::geteuid()) { - rootOwnedFileName = "/opt"; - } - } - qputenv("XDG_RUNTIME_DIR", QFile::encodeName(rootOwnedFileName)); + // set up the environment to point to a place we control + QTemporaryDir tempDir; + QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString())); - // It's very unlikely that /tmp is 0600 or that we can chmod it - // The call below outputs - // "QStandardPaths: wrong ownership on runtime directory /tmp, 0 instead of $UID" - // but we can't reliably expect that it's owned by uid 0, I think. - const uid_t uid = geteuid(); - QTest::ignoreMessage(QtWarningMsg, - qPrintable(QString::fromLatin1("QStandardPaths: wrong ownership on runtime directory " + rootOwnedFileName + ", 0 instead of %1").arg(uid))); - const QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); - QVERIFY2(runtimeDir.isEmpty(), qPrintable(runtimeDir)); + QDir d(tempDir.path()); + qputenv("TMPDIR", QFile::encodeName(tempDir.path())); - // When $XDG_RUNTIME_DIR points to a directory with wrong permissions, QStandardPaths should warn - const QByteArray wrongPermissionFileName = "wrong_permissions"; - QDir::current().mkdir(wrongPermissionFileName); - QFile wrongPermissionFile(wrongPermissionFileName); - const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser; - QVERIFY(wrongPermissionFile.setPermissions(wantedPerms | QFile::ExeGroup)); + QFETCH(RuntimeDirSetup, setup); + QString expected = setup(d); - qputenv("XDG_RUNTIME_DIR", wrongPermissionFileName); - QTest::ignoreMessage(QtWarningMsg, - qPrintable(QString::fromLatin1("QStandardPaths: wrong permissions on runtime directory " + wrongPermissionFileName + ", 7710 instead of 7700"))); - const QString wrongPermissionRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); - QVERIFY(wrongPermissionRuntimeDir.isEmpty()); - QDir::current().rmdir(wrongPermissionFileName); - - // When $XDG_RUNTIME_DIR points to a non-existing directory, QStandardPaths should create it first - const QByteArray nonExistingDir = "does_not_exist"; - qputenv("XDG_RUNTIME_DIR", nonExistingDir); - const QString nonExistingRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); - QVERIFY2(!nonExistingRuntimeDir.compare(nonExistingDir), qPrintable(nonExistingRuntimeDir)); - QVERIFY(QDir::current().exists(nonExistingRuntimeDir)); - QDir::current().rmdir(nonExistingRuntimeDir); - - // When $XDG_RUNTIME_DIR points to a file, QStandardPaths should warn - const QString file = QFINDTESTDATA("tst_qstandardpaths.cpp"); - QVERIFY(!file.isEmpty()); - qputenv("XDG_RUNTIME_DIR", QFile::encodeName(file)); - QTest::ignoreMessage(QtWarningMsg, qPrintable(QString::fromLatin1("QStandardPaths: XDG_RUNTIME_DIR points to '%1' which is not a directory").arg(file))); - const QString noRuntimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); - QVERIFY2(noRuntimeDir.isEmpty(), qPrintable(file)); + QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); + QCOMPARE(runtimeDir, expected); + + if (!runtimeDir.isEmpty()) { + QFileInfo runtimeInfo(runtimeDir); + QVERIFY(runtimeInfo.isDir()); + QVERIFY(!runtimeInfo.isSymLink()); + auto expectedPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner + | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser; + QCOMPARE(QString::number(runtimeInfo.permissions(), 16), + QString::number(expectedPerms, 16)); + } #endif } |