blob: d0fbdb7a2aee4b70cdbba387516c3b6f19719d34 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 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$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qstandardpaths.h>
#include <qdebug.h>
#include <qstandardpaths.h>
#include <qfileinfo.h>
#include <qsysinfo.h>
#include <qregularexpression.h>
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
# include <qt_windows.h>
#endif
#ifdef Q_OS_UNIX
#include <unistd.h>
#include <sys/types.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;
class tst_qstandardpaths : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void dump();
void testDefaultLocations();
void testCustomLocations();
void enableTestMode();
void testLocateAll();
void testDataLocation();
void testAppConfigLocation();
void testFindExecutable_data();
void testFindExecutable();
void testFindExecutableLinkToDirectory();
void testRuntimeDirectory();
void testCustomRuntimeDirectory();
void testAllWritableLocations_data();
void testAllWritableLocations();
void testCleanPath();
void testXdgPathCleanup();
private:
#ifdef Q_XDG_PLATFORM
void setCustomLocations() {
m_localConfigDir = m_localConfigTempDir.path();
m_globalConfigDir = m_globalConfigTempDir.path();
qputenv("XDG_CONFIG_HOME", QFile::encodeName(m_localConfigDir));
qputenv("XDG_CONFIG_DIRS", QFile::encodeName(m_globalConfigDir));
m_localAppDir = m_localAppTempDir.path();
m_globalAppDir = m_globalAppTempDir.path();
qputenv("XDG_DATA_HOME", QFile::encodeName(m_localAppDir));
qputenv("XDG_DATA_DIRS", QFile::encodeName(m_globalAppDir));
}
void setDefaultLocations() {
qputenv("XDG_CONFIG_HOME", QByteArray());
qputenv("XDG_CONFIG_DIRS", QByteArray());
qputenv("XDG_DATA_HOME", QByteArray());
qputenv("XDG_DATA_DIRS", QByteArray());
}
#endif
// Config dirs
QString m_localConfigDir;
QTemporaryDir m_localConfigTempDir;
QString m_globalConfigDir;
QTemporaryDir m_globalConfigTempDir;
// App dirs
QString m_localAppDir;
QTemporaryDir m_localAppTempDir;
QString m_globalAppDir;
QTemporaryDir m_globalAppTempDir;
};
static const char * const enumNames[MaxStandardLocation + 1 - int(QStandardPaths::DesktopLocation)] = {
"DesktopLocation",
"DocumentsLocation",
"FontsLocation",
"ApplicationsLocation",
"MusicLocation",
"MoviesLocation",
"PicturesLocation",
"TempLocation",
"HomeLocation",
"DataLocation",
"CacheLocation",
"GenericDataLocation",
"RuntimeLocation",
"ConfigLocation",
"DownloadLocation",
"GenericCacheLocation",
"GenericConfigLocation",
"AppDataLocation",
"AppConfigLocation"
};
void tst_qstandardpaths::initTestCase()
{
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
// Disable WOW64 redirection, see testFindExecutable()
if (QSysInfo::buildCpuArchitecture() != QSysInfo::currentCpuArchitecture()) {
void *oldMode;
const bool disabledDisableWow64FsRedirection = Wow64DisableWow64FsRedirection(&oldMode) == TRUE;
if (!disabledDisableWow64FsRedirection)
qErrnoWarning("Wow64DisableWow64FsRedirection() failed");
QVERIFY(disabledDisableWow64FsRedirection);
}
#endif // Q_OS_WIN && !Q_OS_WINRT
QVERIFY2(m_localConfigTempDir.isValid(), qPrintable(m_localConfigTempDir.errorString()));
QVERIFY2(m_globalConfigTempDir.isValid(), qPrintable(m_globalConfigTempDir.errorString()));
QVERIFY2(m_localAppTempDir.isValid(), qPrintable(m_localAppTempDir.errorString()));
QVERIFY2(m_globalAppTempDir.isValid(), qPrintable(m_globalAppTempDir.errorString()));
}
void tst_qstandardpaths::dump()
{
#ifdef Q_XDG_PLATFORM
setDefaultLocations();
#endif
// This is not a test. It merely dumps the output.
for (int i = QStandardPaths::DesktopLocation; i <= MaxStandardLocation; ++i) {
QStandardPaths::StandardLocation s = QStandardPaths::StandardLocation(i);
qDebug() << enumNames[i]
<< QStandardPaths::writableLocation(s)
<< QStandardPaths::standardLocations(s);
}
}
void tst_qstandardpaths::testDefaultLocations()
{
#ifdef Q_XDG_PLATFORM
setDefaultLocations();
const QString expectedConfHome = QDir::homePath() + QString::fromLatin1("/.config");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), expectedConfHome);
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation), expectedConfHome);
const QStringList confDirs = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation);
QCOMPARE(confDirs.count(), 2);
QVERIFY(confDirs.contains(expectedConfHome));
QCOMPARE(QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation), confDirs);
const QStringList genericDataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
QCOMPARE(genericDataDirs.count(), 3);
const QString expectedDataHome = QDir::homePath() + QString::fromLatin1("/.local/share");
QCOMPARE(genericDataDirs.at(0), expectedDataHome);
QCOMPARE(genericDataDirs.at(1), QString::fromLatin1("/usr/local/share"));
QCOMPARE(genericDataDirs.at(2), QString::fromLatin1("/usr/share"));
#endif
}
#ifdef Q_XDG_PLATFORM
static void createTestFile(const QString &fileName)
{
QFile file(fileName);
QVERIFY(file.open(QIODevice::WriteOnly));
QVERIFY(file.write("Hello"));
}
#endif
void tst_qstandardpaths::testCustomLocations()
{
#ifdef Q_XDG_PLATFORM
setCustomLocations();
// test writableLocation()
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), m_localConfigDir);
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation), m_localConfigDir);
// test locate()
const QString thisFileName = QString::fromLatin1("aFile");
createTestFile(m_localConfigDir + QLatin1Char('/') + thisFileName);
const QString thisFile = QStandardPaths::locate(QStandardPaths::ConfigLocation, thisFileName);
QVERIFY(!thisFile.isEmpty());
QVERIFY(thisFile.endsWith(thisFileName));
const QString subdir = QString::fromLatin1("subdir");
const QString subdirPath = m_localConfigDir + QLatin1Char('/') + subdir;
QVERIFY(QDir().mkdir(subdirPath));
const QString dir = QStandardPaths::locate(QStandardPaths::ConfigLocation, subdir, QStandardPaths::LocateDirectory);
QCOMPARE(dir, subdirPath);
const QString thisDirAsFile = QStandardPaths::locate(QStandardPaths::ConfigLocation, subdir);
QVERIFY(thisDirAsFile.isEmpty()); // not a file
const QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation);
QCOMPARE(dirs, QStringList() << m_localConfigDir << m_globalConfigDir);
#endif
}
void tst_qstandardpaths::enableTestMode()
{
QVERIFY(!QStandardPaths::isTestModeEnabled());
QStandardPaths::setTestModeEnabled(true);
QVERIFY(QStandardPaths::isTestModeEnabled());
#ifdef Q_XDG_PLATFORM
setCustomLocations(); // for the global config dir
const QString qttestDir = QDir::homePath() + QLatin1String("/.qttest");
// ConfigLocation
const QString configDir = qttestDir + QLatin1String("/config");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), configDir);
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation), configDir);
const QStringList confDirs = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation);
QCOMPARE(confDirs, QStringList() << configDir << m_globalConfigDir);
// GenericDataLocation
const QString dataDir = qttestDir + QLatin1String("/share");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), dataDir);
const QStringList gdDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
QCOMPARE(gdDirs, QStringList() << dataDir << m_globalAppDir);
// GenericCacheLocation
const QString cacheDir = qttestDir + QLatin1String("/cache");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation), cacheDir);
const QStringList cacheDirs = QStandardPaths::standardLocations(QStandardPaths::GenericCacheLocation);
QCOMPARE(cacheDirs, QStringList() << cacheDir);
#endif
// On all platforms, we want to ensure that the writableLocation is different in test mode and real mode.
// Check this for locations where test programs typically write. Not desktop, download, music etc...
typedef QHash<QStandardPaths::StandardLocation, QString> LocationHash;
LocationHash testLocations;
testLocations.insert(QStandardPaths::AppDataLocation, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
testLocations.insert(QStandardPaths::AppLocalDataLocation, QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
testLocations.insert(QStandardPaths::GenericDataLocation, QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
testLocations.insert(QStandardPaths::ConfigLocation, QStandardPaths::writableLocation(QStandardPaths::ConfigLocation));
testLocations.insert(QStandardPaths::GenericConfigLocation, QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation));
testLocations.insert(QStandardPaths::CacheLocation, QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
testLocations.insert(QStandardPaths::GenericCacheLocation, QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation));
// On Windows, what should "Program Files" become, in test mode?
//testLocations.insert(QStandardPaths::ApplicationsLocation, QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
QStandardPaths::setTestModeEnabled(false);
for (LocationHash::const_iterator it = testLocations.constBegin(); it != testLocations.constEnd(); ++it)
QVERIFY2(QStandardPaths::writableLocation(it.key()) != it.value(), qPrintable(it.value()));
// Check that this is also true with no env vars set
#ifdef Q_XDG_PLATFORM
setDefaultLocations();
for (LocationHash::const_iterator it = testLocations.constBegin(); it != testLocations.constEnd(); ++it)
QVERIFY2(QStandardPaths::writableLocation(it.key()) != it.value(), qPrintable(it.value()));
#endif
}
void tst_qstandardpaths::testLocateAll()
{
#ifdef Q_XDG_PLATFORM
setCustomLocations();
const QStringList appsDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "applications", QStandardPaths::LocateDirectory);
QCOMPARE(appsDirs.count(), 0); // they don't exist yet
const QStringList expectedAppsDirs = QStringList() << m_localAppDir + QLatin1String("/applications")
<< m_globalAppDir + QLatin1String("/applications");
QDir().mkdir(expectedAppsDirs.at(0));
QDir().mkdir(expectedAppsDirs.at(1));
const QStringList appsDirs2 = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "applications", QStandardPaths::LocateDirectory);
QCOMPARE(appsDirs2, expectedAppsDirs);
const QStringList appsDirs3 = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
QCOMPARE(appsDirs3, expectedAppsDirs);
const QString thisFileName = QString::fromLatin1("aFile");
const QStringList expectedFiles = QStringList() << m_localConfigDir + QLatin1Char('/') + thisFileName
<< m_globalConfigDir + QLatin1Char('/') + thisFileName;
createTestFile(expectedFiles.at(0));
createTestFile(expectedFiles.at(1));
const QStringList allFiles = QStandardPaths::locateAll(QStandardPaths::ConfigLocation, thisFileName);
QCOMPARE(allFiles, expectedFiles);
#endif
}
void tst_qstandardpaths::testDataLocation()
{
// On all platforms, DataLocation should be GenericDataLocation / organization name / app name
// This allows one app to access the data of another app.
// Android and WinRT are an exception to this case, owing to the fact that
// applications are sandboxed.
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT)
const QString base = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation), base + "/tst_qstandardpaths");
QCoreApplication::instance()->setOrganizationName("Qt");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation), base + "/Qt/tst_qstandardpaths");
QCoreApplication::instance()->setApplicationName("QtTest");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation), base + "/Qt/QtTest");
#endif
#ifdef Q_XDG_PLATFORM
setDefaultLocations();
const QString expectedAppDataDir = QDir::homePath() + QString::fromLatin1("/.local/share/Qt/QtTest");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation), expectedAppDataDir);
const QStringList appDataDirs = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
QCOMPARE(appDataDirs.count(), 3);
QCOMPARE(appDataDirs.at(0), expectedAppDataDir);
QCOMPARE(appDataDirs.at(1), QString::fromLatin1("/usr/local/share/Qt/QtTest"));
QCOMPARE(appDataDirs.at(2), QString::fromLatin1("/usr/share/Qt/QtTest"));
#endif
// reset for other tests
QCoreApplication::setOrganizationName(QString());
QCoreApplication::setApplicationName(QString());
}
void tst_qstandardpaths::testAppConfigLocation()
{
// On all platforms where applications are not sandboxed,
// AppConfigLocation should be GenericConfigLocation / organization name / app name
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT)
const QString base = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation), base + "/tst_qstandardpaths");
QCoreApplication::setOrganizationName("Qt");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation), base + "/Qt/tst_qstandardpaths");
QCoreApplication::setApplicationName("QtTest");
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation), base + "/Qt/QtTest");
// reset for other tests
QCoreApplication::setOrganizationName(QString());
QCoreApplication::setApplicationName(QString());
#endif
}
#ifndef Q_OS_WIN
// Find "sh" on Unix.
// It may exist twice, in /bin/sh and /usr/bin/sh, in that case use the PATH order.
static inline QFileInfo findSh()
{
QLatin1String sh("/sh");
QByteArray pEnv = qgetenv("PATH");
const QLatin1Char pathSep(':');
const QStringList rawPaths = QString::fromLocal8Bit(pEnv.constData()).split(pathSep, Qt::SkipEmptyParts);
foreach (const QString &path, rawPaths) {
if (QFile::exists(path + sh))
return path + sh;
}
return QFileInfo();
}
#endif
void tst_qstandardpaths::testFindExecutable_data()
{
#ifdef SKIP_FINDEXECUTABLE
// Test needs to be skipped or Q_ASSERT below will cancel the test
// and report FAIL regardless of BLACKLIST contents
QSKIP("QTBUG-64404");
#endif
QTest::addColumn<QString>("directory");
QTest::addColumn<QString>("needle");
QTest::addColumn<QString>("expected");
#ifdef Q_OS_WIN
# ifndef Q_OS_WINRT
const QFileInfo cmdFi = QFileInfo(QDir::cleanPath(QString::fromLocal8Bit(qgetenv("COMSPEC"))));
const QString cmdPath = cmdFi.absoluteFilePath();
Q_ASSERT(cmdFi.exists());
QTest::newRow("win-cmd")
<< QString() << QString::fromLatin1("cmd.eXe") << cmdPath;
QTest::newRow("win-full-path")
<< QString() << cmdPath << cmdPath;
QTest::newRow("win-relative-path")
<< cmdFi.absolutePath() << QString::fromLatin1("./cmd.exe") << cmdPath;
QTest::newRow("win-cmd-nosuffix")
<< QString() << QString::fromLatin1("cmd") << cmdPath;
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8) {
// The logo executable on Windows 8 is perfectly suited for testing that the
// suffix mechanism is not thrown off by dots in the name.
// Note: Requires disabling WOW64 redirection, see initTestCase()
const QString logo = QLatin1String("microsoft.windows.softwarelogo.showdesktop");
const QString logoPath = cmdFi.absolutePath() + QLatin1Char('/') + logo + QLatin1String(".exe");
QTest::newRow("win8-logo")
<< QString() << (logo + QLatin1String(".exe")) << logoPath;
QTest::newRow("win8-logo-nosuffix")
<< QString() << logo << logoPath;
}
# endif // Q_OS_WINRT
#else
const QFileInfo shFi = findSh();
Q_ASSERT(shFi.exists());
const QString shPath = shFi.absoluteFilePath();
QTest::newRow("unix-sh")
<< QString() << QString::fromLatin1("sh") << shPath;
QTest::newRow("unix-sh-fullpath")
<< QString() << shPath << shPath;
QTest::newRow("unix-sh-relativepath")
<< QString(shFi.absolutePath()) << QString::fromLatin1("./sh") << shPath;
#endif
QTest::newRow("idontexist")
<< QString() << QString::fromLatin1("idontexist") << QString();
QTest::newRow("empty")
<< QString() << QString() << QString();
}
void tst_qstandardpaths::testFindExecutable()
{
QFETCH(QString, directory);
QFETCH(QString, needle);
QFETCH(QString, expected);
const bool changeDirectory = !directory.isEmpty();
const QString currentDirectory = QDir::currentPath();
if (changeDirectory)
QVERIFY(QDir::setCurrent(directory));
const QString result = QStandardPaths::findExecutable(needle);
if (changeDirectory)
QVERIFY(QDir::setCurrent(currentDirectory));
#ifdef Q_OS_WIN
const Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
#else
const Qt::CaseSensitivity sensitivity = Qt::CaseSensitive;
#endif
QVERIFY2(!result.compare(expected, sensitivity),
qPrintable(QString::fromLatin1("Actual: '%1', Expected: '%2'").arg(result, expected)));
}
void tst_qstandardpaths::testFindExecutableLinkToDirectory()
{
// WinRT has no link support
#ifndef Q_OS_WINRT
// link to directory
const QString target = QDir::tempPath() + QDir::separator() + QLatin1String("link.lnk");
QFile::remove(target);
QFile appFile(QCoreApplication::applicationDirPath());
QVERIFY(appFile.link(target));
QVERIFY(QStandardPaths::findExecutable(target).isEmpty());
QFile::remove(target);
#endif
}
void tst_qstandardpaths::testRuntimeDirectory()
{
#ifdef Q_XDG_PLATFORM
const QString runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
QVERIFY(!runtimeDir.isEmpty());
#endif
}
void tst_qstandardpaths::testCustomRuntimeDirectory()
{
#if defined(Q_OS_UNIX)
if (::getuid() == 0)
QSKIP("Running this test as root doesn't make sense");
#endif
#ifdef Q_XDG_PLATFORM
struct EnvVarRestorer
{
EnvVarRestorer() : origRuntimeDir(qgetenv("XDG_RUNTIME_DIR")) {}
~EnvVarRestorer() { qputenv("XDG_RUNTIME_DIR", origRuntimeDir.constData()); }
const QByteArray origRuntimeDir;
};
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));
// 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));
// 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));
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));
#endif
}
Q_DECLARE_METATYPE(QStandardPaths::StandardLocation)
void tst_qstandardpaths::testAllWritableLocations_data()
{
QTest::addColumn<QStandardPaths::StandardLocation>("location");
QTest::newRow("DesktopLocation") << QStandardPaths::DesktopLocation;
QTest::newRow("DocumentsLocation") << QStandardPaths::DocumentsLocation;
QTest::newRow("FontsLocation") << QStandardPaths::FontsLocation;
QTest::newRow("ApplicationsLocation") << QStandardPaths::ApplicationsLocation;
QTest::newRow("MusicLocation") << QStandardPaths::MusicLocation;
QTest::newRow("MoviesLocation") << QStandardPaths::MoviesLocation;
QTest::newRow("PicturesLocation") << QStandardPaths::PicturesLocation;
QTest::newRow("TempLocation") << QStandardPaths::TempLocation;
QTest::newRow("HomeLocation") << QStandardPaths::HomeLocation;
QTest::newRow("AppLocalDataLocation") << QStandardPaths::AppLocalDataLocation;
QTest::newRow("DownloadLocation") << QStandardPaths::DownloadLocation;
}
void tst_qstandardpaths::testAllWritableLocations()
{
QFETCH(QStandardPaths::StandardLocation, location);
QStandardPaths::writableLocation(location);
QStandardPaths::displayName(location);
// Currently all desktop locations return their writable location
// with "Unix-style" paths (i.e. they use a slash, not backslash).
QString loc = QStandardPaths::writableLocation(location);
if (loc.size() > 1) // workaround for unlikely case of locations that return '/'
QCOMPARE(loc.endsWith(QLatin1Char('/')), false);
QVERIFY(loc.isEmpty() || loc.contains(QLatin1Char('/')));
QVERIFY(!loc.contains(QLatin1Char('\\')));
}
void tst_qstandardpaths::testCleanPath()
{
#if QT_CONFIG(regularexpression)
const QRegularExpression filter(QStringLiteral("\\\\"));
QVERIFY(filter.isValid());
for (int i = 0; i <= QStandardPaths::GenericCacheLocation; ++i) {
const QStringList paths = QStandardPaths::standardLocations(QStandardPaths::StandardLocation(i));
QVERIFY2(paths.filter(filter).isEmpty(),
qPrintable(QString::fromLatin1("Backslash found in %1 %2")
.arg(i).arg(paths.join(QLatin1Char(',')))));
}
#else
QSKIP("regularexpression feature disabled");
#endif
}
void tst_qstandardpaths::testXdgPathCleanup()
{
#ifdef Q_XDG_PLATFORM
setCustomLocations();
const QString uncleanGlobalAppDir = "/./" + QFile::encodeName(m_globalAppDir);
qputenv("XDG_DATA_DIRS", QFile::encodeName(uncleanGlobalAppDir) + "::relative/path");
const QStringList appsDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
QVERIFY(!appsDirs.contains("/applications"));
QVERIFY(!appsDirs.contains(uncleanGlobalAppDir + "/applications"));
QVERIFY(!appsDirs.contains("relative/path/applications"));
#endif
}
QTEST_MAIN(tst_qstandardpaths)
#include "tst_qstandardpaths.moc"