File indexing completed on 2024-04-14 14:19:44

0001 /* This file is part of the KDE libraries
0002     Copyright (c) 2006, 2011 David Faure <faure@kde.org>
0003 
0004     This library is free software; you can redistribute it and/or
0005     modify it under the terms of the GNU Library General Public
0006     License version 2 as published by the Free Software Foundation.
0007 
0008     This library is distributed in the hope that it will be useful,
0009     but WITHOUT ANY WARRANTY; without even the implied warranty of
0010     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0011     Library General Public License for more details.
0012 
0013     You should have received a copy of the GNU Library General Public License
0014     along with this library; see the file COPYING.LIB.  If not, write to
0015     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0016     Boston, MA 02110-1301, USA.
0017 */
0018 
0019 #include "kstandarddirstest.h"
0020 #include "qstandardpaths.h"
0021 
0022 #include "qtest.h"
0023 
0024 QTEST_GUILESS_MAIN(KStandarddirsTest)
0025 
0026 #include <config-kstandarddirs.h>
0027 #include <kdebug.h>
0028 #include <kstandarddirs.h>
0029 #include <kcomponentdata.h>
0030 #include <kconfig.h>
0031 #include <kglobal.h>
0032 #include <qtemporarydir.h>
0033 #include <QDebug>
0034 #include <QTest>
0035 #include <kconfiggroup.h>
0036 #include <QFile>
0037 
0038 // we need case-insensitive comparison of file paths on windows
0039 #ifdef Q_OS_WIN
0040 #define QCOMPARE_PATHS(x,y) QCOMPARE(QString(x).toLower(), QString(y).toLower())
0041 #define PATH_SENSITIVITY Qt::CaseInsensitive
0042 #define EXT ".exe"
0043 #else
0044 #define QCOMPARE_PATHS(x,y) QCOMPARE(QString(x), QString(y))
0045 #define PATH_SENSITIVITY Qt::CaseSensitive
0046 #define EXT ""
0047 #endif
0048 
0049 void KStandarddirsTest::initTestCase()
0050 {
0051     QString kconfig_compilerLocation = QStringLiteral(KCONFIG_COMPILER_LOCATION);
0052     if (kconfig_compilerLocation.startsWith(CMAKE_INSTALL_PREFIX)) {
0053         m_canFindKConfig = true;
0054     } else {
0055         // the user needs to set KDEDIRS properly!
0056         QStringList kdedirs = QFile::decodeName(qgetenv("KDEDIRS")).split(':');
0057         m_canFindKConfig = false;
0058         foreach (QString dirName, kdedirs) {
0059             if (!dirName.isEmpty() && kconfig_compilerLocation.startsWith(dirName)) {
0060                 m_canFindKConfig = true;
0061             }
0062         }
0063     }
0064 
0065     // canonicalPath() to resolve symlinks (e.g. on FreeBSD where /home is a symlink to /usr/home),
0066     // this matches what KGlobal::dirs()->realPath() would do, but we can't use it before setting
0067     // the env vars, it would mess up the unit test
0068     const QString homePath = QDir::home().canonicalPath();
0069     m_configHome = homePath + QLatin1String("/.kde-unit-test/xdg/config");
0070 
0071     qputenv("XDG_CONFIG_HOME", QFile::encodeName(m_configHome));
0072 
0073     m_dataHome = homePath + QLatin1String("/.kde-unit-test/xdg/local");
0074     qputenv("XDG_DATA_HOME", QFile::encodeName(m_dataHome));
0075 
0076     const QString configDirs = QDir::currentPath() + "/xdg";
0077     qputenv("XDG_CONFIG_DIRS", QFile::encodeName(configDirs));
0078 
0079     qunsetenv("XDG_DATA_DIRS");
0080 
0081     QFile::remove(KGlobal::dirs()->saveLocation("config") + "kstandarddirstestrc");
0082 
0083     // Create a main component data so that testAppData doesn't suddenly change the main component
0084     // data.
0085     KComponentData mainData("kstandarddirstest");
0086 
0087     // Must initialize KStandardDirs only after all the setenv() calls.
0088     QCOMPARE(KGlobal::dirs()->localxdgconfdir(), QString(m_configHome + '/'));
0089 }
0090 
0091 void KStandarddirsTest::testSaveLocation()
0092 {
0093     const QString saveLocConfig = KGlobal::dirs()->saveLocation("config");
0094     QCOMPARE_PATHS(saveLocConfig, KGlobal::dirs()->localxdgconfdir());
0095     const QString saveLocXdgConfig = KGlobal::dirs()->saveLocation("xdgconf");
0096     QCOMPARE_PATHS(saveLocConfig, saveLocXdgConfig); // same result
0097 
0098     const QString saveLocAppData = KGlobal::dirs()->saveLocation("appdata");
0099     QCOMPARE_PATHS(saveLocAppData, m_dataHome + "/kstandarddirstest/");
0100 
0101     const QString saveTmp = KGlobal::dirs()->saveLocation("tmp");
0102     QCOMPARE_PATHS(saveTmp, QDir::tempPath() + '/');
0103 }
0104 
0105 void KStandarddirsTest::testLocateLocal()
0106 {
0107     const QString configLocal = KStandardDirs::locateLocal("config", "ksomethingrc");
0108     // KStandardDirs resolves symlinks, so we must compare with canonicalPath()
0109     QCOMPARE_PATHS(configLocal, m_configHome + "/ksomethingrc");
0110 }
0111 
0112 void KStandarddirsTest::testResourceDirs()
0113 {
0114     const QStringList configDirs = KGlobal::dirs()->resourceDirs("config");
0115     Q_FOREACH (const QString &dir, configDirs) {
0116         QVERIFY2(dir.endsWith("xdg/")
0117                  || dir.endsWith("share/config/") // KDE4 compat path
0118                  || dir.endsWith(".kde-unit-test/xdg/config/"), qPrintable(dir));
0119     }
0120 }
0121 
0122 void KStandarddirsTest::testAppData()
0123 {
0124     // This API is gone
0125 #if 0
0126     // In addition to testSaveLocation(), we want to also check other KComponentDatas
0127     KComponentData cData("foo");
0128     const QString fooAppData = cData.dirs()->saveLocation("appdata");
0129     QCOMPARE_PATHS(fooAppData, m_dataHome + "/foo/");
0130 #endif
0131 }
0132 
0133 void KStandarddirsTest::testChangeSaveLocation()
0134 {
0135     KStandardDirs cData;
0136     QCOMPARE_PATHS(cData.saveLocation("config"), m_configHome + "/");
0137     // Can we change the save location?
0138     const QString newSaveLoc = m_configHome + "/newconfigdir/";
0139     //cData.addResourceDir("config", newSaveLoc); // can't be done, absolute paths have less priority than relative paths
0140     cData.addResourceType("config", nullptr, "newconfigdir");
0141     QCOMPARE_PATHS(KStandardDirs::realPath(cData.saveLocation("config")), newSaveLoc);
0142 }
0143 
0144 static bool isKdeLibs4supportInstalled()
0145 {
0146     return QFile::exists(CMAKE_INSTALL_PREFIX "/bin/kf5-config");
0147 }
0148 
0149 void KStandarddirsTest::testFindResource()
0150 {
0151     if (!m_canFindKConfig) {
0152         QSKIP("KDEDIRS does not contain the KConfig prefix");
0153     }
0154 
0155     const QString bin = KGlobal::dirs()->findResource("exe", "kf5/kconf_update" EXT);
0156     QVERIFY(!bin.isEmpty());
0157 #ifdef Q_OS_WIN
0158     QVERIFY(bin.endsWith("bin/kconf_update.exe"));
0159 #else
0160     QVERIFY(bin.endsWith("libexec/kf5/kconf_update"));
0161 #endif
0162     QVERIFY(!QDir::isRelativePath(bin));
0163 
0164     const QString data = KGlobal::dirs()->findResource("data", "dbus-1/interfaces/kf5_org.kde.JobView.xml");
0165     QVERIFY(!data.isEmpty());
0166     QVERIFY(data.endsWith(QLatin1String("dbus-1/interfaces/kf5_org.kde.JobView.xml")));
0167     QVERIFY(!QDir::isRelativePath(data));
0168 }
0169 
0170 static bool oneEndsWith(const QStringList &lst, const QString &str)
0171 {
0172     for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
0173         if ((*it).endsWith(str)) {
0174             return true;
0175         }
0176     }
0177     return false;
0178 }
0179 
0180 void KStandarddirsTest::testFindAllResources()
0181 {
0182     if (!isKdeLibs4supportInstalled()) {
0183         QSKIP("KDELibs4Support is not installed yet");
0184     }
0185 
0186     const QStringList dbusInterfaceFiles = KGlobal::dirs()->findAllResources("data", "dbus-1/interfaces/");
0187     QVERIFY(!dbusInterfaceFiles.isEmpty());
0188     QVERIFY(dbusInterfaceFiles.count() > 20);   // I have 21 here, installed by kdelibs.
0189 
0190     // Create a local config file, the file will be used as expected result
0191     const QString localConfigFile = m_configHome + "/foorc";
0192     QFile::remove(localConfigFile);
0193     KConfig foorc("foorc");
0194     KConfigGroup dummyGroup(&foorc, "Dummy");
0195     dummyGroup.writeEntry("someEntry", true);
0196     dummyGroup.sync();
0197     QVERIFY2(QFile::exists(localConfigFile), qPrintable(localConfigFile));
0198 
0199     const QStringList configFiles = KGlobal::dirs()->findAllResources("config");
0200     QVERIFY(!configFiles.isEmpty());
0201     //qDebug() << configFiles;
0202     QVERIFY(oneEndsWith(configFiles, "etc/xdg/kdebugrc"));
0203     QVERIFY(oneEndsWith(configFiles, "etc/xdg/kdebug.areas"));
0204     QVERIFY(oneEndsWith(configFiles, "kde-unit-test/xdg/config/foorc"));
0205     QVERIFY(!oneEndsWith(configFiles, "etc/xdg/colors/Web.colors"));     // recursive was false
0206 
0207     {
0208         const QStringList configFilesRecursive = KGlobal::dirs()->findAllResources("config", QString(),
0209                 KStandardDirs::Recursive);
0210         QVERIFY(!configFilesRecursive.isEmpty());
0211         QVERIFY(configFilesRecursive.count() > 5);   // I have 15 here
0212         QVERIFY(oneEndsWith(configFilesRecursive, "etc/xdg/kdebugrc"));
0213         QVERIFY(oneEndsWith(configFilesRecursive, "etc/xdg/colors/Web.colors"));     // proves that recursive worked
0214     }
0215 
0216     {
0217         const QStringList configFilesRecursiveWithFilter = KGlobal::dirs()->findAllResources("config", "*rc",
0218                 KStandardDirs::Recursive);
0219         QVERIFY(!configFilesRecursiveWithFilter.isEmpty());
0220         //qDebug() << configFilesRecursiveWithFilter;
0221         QVERIFY(configFilesRecursiveWithFilter.count() >= 2);   // foorc, kdebugrc
0222         QVERIFY(oneEndsWith(configFilesRecursiveWithFilter, "kde-unit-test/xdg/config/foorc"));
0223         QVERIFY(oneEndsWith(configFilesRecursiveWithFilter, "etc/xdg/kdebugrc"));
0224         QVERIFY(!oneEndsWith(configFilesRecursiveWithFilter, "etc/xdg/colors/Web.colors"));     // didn't match the filter
0225     }
0226 
0227     {
0228         QStringList fileNames;
0229         const QStringList configFilesWithFilter = KGlobal::dirs()->findAllResources("config", "*rc", KStandardDirs::NoDuplicates, fileNames);
0230         QVERIFY(!configFilesWithFilter.isEmpty());
0231         QVERIFY2(configFilesWithFilter.count() >= 2, qPrintable(configFilesWithFilter.join(",")));
0232         QVERIFY(oneEndsWith(configFilesWithFilter, "kde-unit-test/xdg/config/foorc"));
0233         QVERIFY(oneEndsWith(configFilesWithFilter, "kdebugrc"));     // either global (etc/xdg/) or local (XDG_HOME)
0234         QVERIFY(!oneEndsWith(configFilesWithFilter, "etc/xdg/ui/ui_standards.rc"));     // recursive not set
0235         QVERIFY(!oneEndsWith(configFilesWithFilter, "etc/xdg/accept-languages.codes"));     // didn't match the filter
0236         QCOMPARE(fileNames.count(), configFilesWithFilter.count());
0237         QVERIFY(fileNames.contains("kdebugrc"));
0238     }
0239 
0240 #if 0
0241     list = t.findAllResources("html", "en/*/index.html", false);
0242     for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
0243         kDebug() << "docs " << (*it).toLatin1().constData();
0244     }
0245 
0246     list = t.findAllResources("html", "*/*/*.html", false);
0247     for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
0248         kDebug() << "docs " << (*it).toLatin1().constData();
0249     }
0250 #endif
0251 }
0252 
0253 void KStandarddirsTest::testFindAllResourcesNewDir()
0254 {
0255     const QString dir = m_dataHome + "/cmake/modules";
0256     const QString fileName = dir + "/unittest.testfile";
0257     QFile::remove(fileName);
0258     const QStringList origFiles = KGlobal::dirs()->findAllResources("data", "cmake/modules/");
0259     const int origCount = origFiles.count();
0260 
0261     QDir().mkpath(dir);
0262     QFile file(fileName);
0263     QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text));
0264     file.write("foo");
0265     file.close();
0266 
0267     const int newCount = KGlobal::dirs()->findAllResources("data", "cmake/modules/").count();
0268     QCOMPARE(newCount, origCount + 1);
0269     file.remove();
0270     QDir().rmpath(dir);
0271 }
0272 
0273 void KStandarddirsTest::testFindDirs()
0274 {
0275     if (!isKdeLibs4supportInstalled()) {
0276         QSKIP("KDELibs4Support is not installed yet");
0277     }
0278 
0279     const QString t = KStandardDirs::locateLocal("data", "locale/");
0280     QCOMPARE(t, QString(m_dataHome + "/locale/"));
0281     const QStringList dirs = KGlobal::dirs()->findDirs("data", "locale");
0282     QVERIFY(!dirs.isEmpty());
0283     QVERIFY2(dirs.count() >= 2, qPrintable(dirs.join(","))); // at least local and global
0284     //qDebug() << dirs;
0285 }
0286 
0287 void KStandarddirsTest::testFindResourceDir()
0288 {
0289     if (!isKdeLibs4supportInstalled()) {
0290         QSKIP("KDELibs4Support is not installed yet");
0291     }
0292 
0293     const QString configDir = KGlobal::dirs()->findResourceDir("config", "foorc");
0294     QVERIFY(!configDir.isEmpty());
0295     QVERIFY2(configDir.endsWith(QLatin1String("/xdg/config/")), qPrintable(configDir));
0296 }
0297 
0298 void KStandarddirsTest::testFindExeLibExec()
0299 {
0300 #ifndef Q_OS_UNIX
0301     QSKIP("non-UNIX system");
0302 #endif
0303     if (!isKdeLibs4supportInstalled()) {
0304         // KStandardDirs::findExe only finds libexec executables in the installed location
0305         QSKIP("KDELibs4Support is not installed yet");
0306     }
0307 
0308     // findExe with a result in libexec
0309     const QString libexe = KGlobal::dirs()->findExe("kf5/fileshareset");
0310     QVERIFY(!libexe.isEmpty());
0311     QVERIFY(libexe.endsWith(LIB_INSTALL_DIR "/libexec/kf5/fileshareset" EXT, PATH_SENSITIVITY));
0312 }
0313 
0314 void KStandarddirsTest::testFindExe()
0315 {
0316     if (!m_canFindKConfig) {
0317         QSKIP("KDEDIRS does not contain the KConfig prefix");
0318     }
0319 
0320     const QString exeFileName = QStringLiteral("kreadconfig5");
0321 
0322     // findExe with a result in bin
0323     const QString binexe = KGlobal::dirs()->findExe(exeFileName);
0324     QVERIFY(!binexe.isEmpty());
0325     QCOMPARE_PATHS(binexe, QStandardPaths::findExecutable(exeFileName));
0326 
0327     // Check the "exe" resource too
0328     QString binexePath1 = KStandardDirs::realFilePath(binexe);
0329     QString binexePath2 = KGlobal::dirs()->locate("exe", exeFileName);
0330     QCOMPARE_PATHS(binexePath1, binexePath2);
0331 
0332     // Check realFilePath behavior with complete command lines, like KRun does
0333     const QString cmd = binexe + " -c foo -x bar";
0334     const QString fromKStdDirs = KStandardDirs::realFilePath(cmd);
0335     QCOMPARE(fromKStdDirs, cmd);
0336     const QString fromQFileInfo = QFileInfo(cmd).canonicalFilePath();
0337     QVERIFY2(fromQFileInfo.isEmpty(), qPrintable(QString("QFileInfo(\"" + cmd + "\").canonicalFilePath() returned \"" + fromQFileInfo + "\""))); // !! different result, since this doesn't exist as a file
0338 
0339 #ifdef Q_OS_UNIX
0340     // findExe with relative path
0341     const QString pwd = QDir::currentPath();
0342     QDir::setCurrent("/bin");
0343     QStringList possibleResults;
0344     possibleResults << QString::fromLatin1("/bin/sh") << QString::fromLatin1("/usr/bin/sh");
0345     const QString sh = KGlobal::dirs()->findExe("./sh");
0346     if (!possibleResults.contains(sh)) {
0347         kDebug() << sh;
0348     }
0349     QVERIFY(possibleResults.contains(sh));
0350     QDir::setCurrent(pwd);
0351 #endif
0352 
0353 #if 0 // Broken test, findExe doesn't look in kdehome, but in kdehome/bin (in kde4) and in $PATH.
0354 #ifdef Q_OS_UNIX
0355     QFile home(m_kdehome);
0356     const QString target = m_kdehome + "/linktodir";
0357     home.link(target);
0358     QVERIFY(KGlobal::dirs()->findExe(target).isEmpty());
0359 #endif
0360 #endif
0361 
0362 #ifdef Q_OS_UNIX
0363     // findExe for a binary not part of KDE
0364     const QString ls = KGlobal::dirs()->findExe("ls");
0365     QVERIFY(!ls.isEmpty());
0366     QVERIFY(ls.endsWith(QLatin1String("bin/ls")));
0367 #endif
0368 
0369     // findExe with no result
0370     const QString idontexist = KGlobal::dirs()->findExe("idontexist");
0371     QVERIFY(idontexist.isEmpty());
0372 
0373     // findExe with empty string
0374     const QString empty = KGlobal::dirs()->findExe("");
0375     QVERIFY(empty.isEmpty());
0376 }
0377 
0378 void KStandarddirsTest::testLocate()
0379 {
0380     QString textPlain = "text/x-patch.xml";
0381     Q_FOREACH (const QString &path, KGlobal::dirs()->resourceDirs("xdgdata-mime")) {
0382         if (QFile::exists(path + textPlain)) {
0383             textPlain = path + textPlain;
0384             break;
0385         }
0386     }
0387     if (textPlain == "text/x-patch.xml") {
0388         QSKIP("xdg-share-mime not installed");
0389     }
0390 
0391     const QString res = KGlobal::dirs()->locate("xdgdata-mime", "text/x-patch.xml");
0392     QCOMPARE_PATHS(res, textPlain);
0393 }
0394 
0395 void KStandarddirsTest::testRelativeLocation()
0396 {
0397     if (!isKdeLibs4supportInstalled()) {
0398         QSKIP("KDELibs4Support is not installed yet");
0399     }
0400 
0401     const QString file = "kdebugrc";
0402     QString located = KGlobal::dirs()->locate("config", file);
0403     QCOMPARE_PATHS(KGlobal::dirs()->relativeLocation("config", located), file);
0404 }
0405 
0406 void KStandarddirsTest::testAddResourceType()
0407 {
0408     if (!isKdeLibs4supportInstalled()) {
0409         QSKIP("KDELibs4Support is not installed yet");
0410     }
0411 
0412     QString ret = KStandardDirs::locate("widgets", "pics/kdialog.png");
0413     QCOMPARE(ret, QString()); // normal, there's no "widgets" resource in kstandarddirs by default
0414 
0415     KGlobal::dirs()->addResourceType("widgets", "data", "kf5/widgets/");
0416     ret = KStandardDirs::locate("widgets", "pics/kdialog.png");
0417     QVERIFY(!ret.isEmpty());
0418 
0419     ret = KStandardDirs::locate("widgets", "pics/kdoublenuminput.png");
0420     QVERIFY(!ret.isEmpty());
0421 
0422     const QStringList files = KGlobal::dirs()->findAllResources("widgets", "pics/*", KStandardDirs::NoDuplicates);
0423     QVERIFY(files.count() >= 10);
0424 
0425     KGlobal::dirs()->addResourceType("xdgdata-ontology", nullptr, "ontology");
0426     const QStringList ontologyDirs = KGlobal::dirs()->resourceDirs("xdgdata-ontology");
0427     QCOMPARE(ontologyDirs.first(), KStandardDirs::realPath(QString(qgetenv("XDG_DATA_HOME")) + "/ontology/"));
0428     if (QFile::exists("/usr/share/ontology") &&
0429             QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).contains("/usr/share")) {
0430         QVERIFY(ontologyDirs.contains("/usr/share/ontology/"));
0431     }
0432 }
0433 
0434 void KStandarddirsTest::testAddResourceDir()
0435 {
0436     const QString dir = QFileInfo(QFINDTESTDATA("kstandarddirstest.cpp")).absolutePath();
0437     const QString file = "kstandarddirstest.cpp";
0438     QString ret = KStandardDirs::locate("here", file);
0439     QCOMPARE(ret, QString()); // not set up yet
0440 
0441     KGlobal::dirs()->addResourceDir("here", dir);
0442     ret = KStandardDirs::locate("here", file);
0443     QCOMPARE_PATHS(ret, KStandardDirs::realPath(dir) + "kstandarddirstest.cpp");
0444 }
0445 
0446 void KStandarddirsTest::testSetXdgDataDirs()
0447 {
0448     // By default we should have KDEDIR/share/applications in `kf5-config --path xdgdata-apps`
0449     const QStringList dirs = KGlobal::dirs()->resourceDirs("xdgdata-apps");
0450     const QString kdeDataApps = KStandardDirs::realPath(CMAKE_INSTALL_PREFIX "/share/applications/");
0451     if (!dirs.contains(kdeDataApps)) {
0452         kDebug() << "ERROR:" << kdeDataApps << "not in" << dirs;
0453         kDebug() << "XDG_DATA_DIRS=" << qgetenv("XDG_DATA_DIRS");
0454         kDebug() << "installprefix=" << KStandardDirs::installPath("kdedir");
0455         kDebug() << "installdir=" << KStandardDirs::installPath("xdgdata-apps");
0456         kDebug() << "GenericDataLocation=" << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
0457     }
0458     QVERIFY(dirs.contains(kdeDataApps, PATH_SENSITIVITY));
0459 
0460     // When setting XDG_DATA_DIRS this should still be true
0461     const QString localApps = m_dataHome + "/applications/";
0462     QVERIFY(KStandardDirs::makeDir(localApps));
0463 
0464     // canonicalPath: see the comment in initTestCase
0465     const QString customDataDir = QDir::home().canonicalPath() + QLatin1String("/.kde-unit-test/xdg/global");
0466     qputenv("XDG_DATA_DIRS", QFile::encodeName(customDataDir));
0467     QVERIFY(QDir(customDataDir).mkpath("applications"));
0468     KStandardDirs newStdDirs;
0469     const QStringList newDirs = newStdDirs.resourceDirs("xdgdata-apps");
0470     //qDebug() << newDirs;
0471     QVERIFY(newDirs.contains(kdeDataApps, PATH_SENSITIVITY));
0472     QVERIFY(newDirs.contains(localApps, PATH_SENSITIVITY));
0473     QVERIFY(newDirs.contains(customDataDir + "/applications/", PATH_SENSITIVITY));
0474 }
0475 
0476 void KStandarddirsTest::testRestrictedResources()
0477 {
0478     // Ensure we have a local xdgdata-apps dir
0479     QFile localFile(KStandardDirs::locateLocal("xdgdata-apps", "foo.desktop"));
0480     QVERIFY(localFile.open(QIODevice::WriteOnly | QIODevice::Text));
0481     localFile.write("foo");
0482     localFile.close();
0483     const QString localAppsDir = KStandardDirs::realPath(QFileInfo(localFile).absolutePath() + '/');
0484     QVERIFY(!localAppsDir.contains("foo.desktop"));
0485     // Ensure we have a local share/kstandarddirstest dir
0486     const QString localDataDir = KStandardDirs::locateLocal("data", "kstandarddirstest/");
0487     QVERIFY(!localDataDir.isEmpty());
0488     QVERIFY(QFile::exists(localDataDir));
0489     const QString localOtherDataDir = KStandardDirs::locateLocal("data", "other/");
0490     QVERIFY(!localOtherDataDir.isEmpty());
0491 
0492     // Check unrestricted results first
0493     const QStringList appsDirs = KGlobal::dirs()->resourceDirs("xdgdata-apps");
0494     QCOMPARE_PATHS(appsDirs.first(), localAppsDir);
0495     const QString kdeDataApps = KStandardDirs::realPath(CMAKE_INSTALL_PREFIX "/share/applications/");
0496     QVERIFY(appsDirs.contains(kdeDataApps, PATH_SENSITIVITY));
0497     const QStringList dataDirs = KGlobal::dirs()->findDirs("data", "kstandarddirstest");
0498     QCOMPARE_PATHS(dataDirs.first(), localDataDir);
0499     const QStringList otherDataDirs = KGlobal::dirs()->findDirs("data", "other");
0500     QCOMPARE_PATHS(otherDataDirs.first(), localOtherDataDir);
0501 
0502     // Initialize restrictions.
0503     // Need a new componentdata to trigger restricted-resource initialization
0504     // And we need to write the config _before_ creating the KStandardDirs.
0505     KConfig foorc("kstandarddirstestrc");
0506     KConfigGroup restrictionsGroup(&foorc, "KDE Resource Restrictions");
0507     restrictionsGroup.writeEntry("xdgdata-apps", false);
0508     restrictionsGroup.writeEntry("data_kstandarddirstest", false);
0509     restrictionsGroup.sync();
0510 
0511     // Check restrictions.
0512     //KComponentData cData("foo");
0513     KStandardDirs *dirs = new KStandardDirs;
0514     dirs->addCustomized(&foorc); // like KGlobal::dirs() does
0515     QVERIFY(dirs->isRestrictedResource("xdgdata-apps"));
0516     QVERIFY(dirs->isRestrictedResource("data", "kstandarddirstest"));
0517 
0518     const QStringList newAppsDirs = dirs->resourceDirs("xdgdata-apps");
0519     QVERIFY(newAppsDirs.contains(kdeDataApps, PATH_SENSITIVITY));
0520     QVERIFY(!newAppsDirs.contains(localAppsDir, PATH_SENSITIVITY)); // restricted!
0521     const QStringList newDataDirs = dirs->findDirs("data", "kstandarddirstest");
0522     QVERIFY(!newDataDirs.contains(localDataDir, PATH_SENSITIVITY)); // restricted!
0523     const QStringList newOtherDataDirs = dirs->findDirs("data", "other");
0524     QVERIFY(newOtherDataDirs.contains(localOtherDataDir, PATH_SENSITIVITY)); // not restricted!
0525 
0526     restrictionsGroup.deleteGroup();
0527     localFile.remove();
0528     delete dirs;
0529 }
0530 
0531 void KStandarddirsTest::testSymlinkResolution()
0532 {
0533     // On FreeBSD it is common to have a symlink /home -> /usr/home,
0534     // which messes with all the comparisons where **some** code paths
0535     // return a canonicalized path and some do not.
0536     if (QDir::homePath().compare(QFileInfo(QDir::homePath() + '/').canonicalFilePath(), PATH_SENSITIVITY) != 0) {
0537         QSKIP("HOME contains a symlink, not supported");
0538     }
0539 #ifndef Q_OS_WIN
0540     // This makes the save location for the david resource, "<XDG_DATA_HOME>/symlink/test/"
0541     // where symlink points to "real", and the subdir test will be created later
0542     // This used to confuse KStandardDirs and make it return unresolved paths,
0543     // and thus making comparisons fail later on in KConfig.
0544     QString baseDir = m_dataHome;
0545     const QString symlink = baseDir + "/symlink";
0546     const QString expected = baseDir + "/real/test/";
0547     QDir d_(baseDir + "/real");
0548     QVERIFY(d_.removeRecursively());
0549     QVERIFY(QDir(baseDir).mkdir("real"));
0550     QFile::remove(symlink);
0551     QVERIFY(!QFile::exists(symlink));
0552     QVERIFY(QFile::link("real", symlink));
0553     QVERIFY(QFileInfo(symlink).isSymLink());
0554     QVERIFY(!QFile::exists(expected));
0555     KGlobal::dirs()->addResourceType("david", nullptr, "symlink/test");
0556     QVERIFY(!QFile::exists(expected));
0557     const QString saveLoc = KGlobal::dirs()->resourceDirs("david").first();
0558     QVERIFY(!QFile::exists(expected));
0559     // The issue at this point is that saveLoc does not actually exist yet.
0560     QVERIFY(QDir(saveLoc).canonicalPath().isEmpty()); // this is why we can't use canonicalPath
0561     QVERIFY(!QFile::exists(saveLoc));
0562     QCOMPARE(saveLoc, KStandardDirs::realPath(saveLoc)); // must be resolved
0563     QCOMPARE(saveLoc, expected);
0564     QVERIFY(QDir(baseDir).mkpath("real/test")); // KConfig calls mkdir on its own, we simulate that here
0565     const QString sameSaveLoc = KGlobal::dirs()->resourceDirs("david").first();
0566     QCOMPARE(sameSaveLoc, saveLoc);
0567     QCOMPARE(sameSaveLoc, KGlobal::dirs()->saveLocation("david"));
0568 
0569     // While we're here...
0570     QCOMPARE(KStandardDirs::realPath(QString()), QString());
0571     QCOMPARE(KStandardDirs::realPath(QString("/")), QString("/"));
0572 
0573     QCOMPARE(KStandardDirs::realPath(QString("/does_not_exist/")), QString("/does_not_exist/"));
0574 #endif
0575 }
0576 
0577 #include <QThreadPool>
0578 #include <QFutureSynchronizer>
0579 #include <qtconcurrentrun.h>
0580 
0581 // To find multithreading bugs: valgrind --tool=helgrind ./kstandarddirstest testThreads
0582 void KStandarddirsTest::testThreads()
0583 {
0584     if (!isKdeLibs4supportInstalled()) {
0585         QSKIP("KDELibs4Support is not installed yet");
0586     }
0587     if (!m_canFindKConfig) {
0588         QSKIP("KDEDIRS does not contain the KConfig prefix");
0589     }
0590 
0591     QThreadPool::globalInstance()->setMaxThreadCount(6);
0592     QFutureSynchronizer<void> sync;
0593     sync.addFuture(QtConcurrent::run(this, &KStandarddirsTest::testLocateLocal));
0594     sync.addFuture(QtConcurrent::run(this, &KStandarddirsTest::testSaveLocation));
0595     sync.addFuture(QtConcurrent::run(this, &KStandarddirsTest::testAppData));
0596     sync.addFuture(QtConcurrent::run(this, &KStandarddirsTest::testFindResource));
0597     sync.addFuture(QtConcurrent::run(this, &KStandarddirsTest::testFindAllResources));
0598     sync.addFuture(QtConcurrent::run(this, &KStandarddirsTest::testLocate));
0599     sync.addFuture(QtConcurrent::run(this, &KStandarddirsTest::testRelativeLocation));
0600     sync.waitForFinished();
0601 }
0602 
0603 #include "moc_kstandarddirstest.cpp"