File indexing completed on 2024-04-28 15:19:33

0001 /*
0002     SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 #include "kdesktopfiletest.h"
0007 #include "helper.h"
0008 #include <kconfiggroup.h>
0009 #include <ksharedconfig.h>
0010 #include <qtemporaryfile.h>
0011 
0012 #include "kdesktopfile.h"
0013 
0014 #include <QTest>
0015 
0016 #if defined(Q_OS_UNIX)
0017 #include <unistd.h>
0018 #endif
0019 
0020 QTEST_MAIN(KDesktopFileTest)
0021 
0022 void KDesktopFileTest::initTestCase()
0023 {
0024     QStandardPaths::setTestModeEnabled(true);
0025 
0026     KConfigGroup actionRestrictions(KSharedConfig::openConfig(), "KDE Action Restrictions");
0027     actionRestrictions.writeEntry("someBlockedAction", false);
0028 }
0029 
0030 void KDesktopFileTest::testRead()
0031 {
0032     QTemporaryFile file(QStringLiteral("testReadXXXXXX.desktop"));
0033     QVERIFY(file.open());
0034     const QString fileName = file.fileName();
0035     QTextStream ts(&file);
0036     ts << "[Desktop Entry]\n"
0037           "Type= Application\n"
0038           "Name=My Application\n"
0039           "Icon = foo\n"
0040           "MimeType =text/plain;image/png;\n"
0041           "\n";
0042     file.close();
0043     QVERIFY(QFile::exists(fileName));
0044     QVERIFY(KDesktopFile::isDesktopFile(fileName));
0045     KDesktopFile df(fileName);
0046     QCOMPARE(df.readType(), QString::fromLatin1("Application"));
0047     QVERIFY(df.hasApplicationType());
0048     QCOMPARE(df.readName(), QString::fromLatin1("My Application"));
0049     QCOMPARE(df.readIcon(), QString::fromLatin1("foo"));
0050     QCOMPARE(df.readMimeTypes(), QStringList() << QString::fromLatin1("text/plain") << QString::fromLatin1("image/png"));
0051     QVERIFY(!df.hasLinkType());
0052     QCOMPARE(df.fileName(), QFileInfo(fileName).canonicalFilePath());
0053 }
0054 
0055 #if KCONFIGCORE_ENABLE_DEPRECATED_SINCE(5, 0)
0056 void KDesktopFileTest::testReadDirectory()
0057 {
0058     QTemporaryFile file(QStringLiteral("testReadDirectoryXXXXXX.directory"));
0059     QVERIFY(file.open());
0060     const QString fileName = file.fileName();
0061     QTextStream ts(&file);
0062     ts << "[Desktop Entry]\n"
0063           "Type=Directory\n"
0064           "SortOrder=2.desktop;1.desktop;\n"
0065           "\n";
0066     file.close();
0067     QVERIFY(QFile::exists(fileName));
0068     KDesktopFile df(fileName);
0069     QCOMPARE(df.readType(), QString::fromLatin1("Directory"));
0070     QCOMPARE(df.sortOrder(), QStringList() << QString::fromLatin1("2.desktop") << QString::fromLatin1("1.desktop"));
0071 }
0072 #endif
0073 
0074 void KDesktopFileTest::testReadLocalized_data()
0075 {
0076     QTest::addColumn<QLocale>("locale");
0077     QTest::addColumn<QString>("translation");
0078 
0079     const QString german = QStringLiteral("Meine Anwendung");
0080     const QString swiss = QStringLiteral("Mein Anwendungsli");
0081 
0082     QTest::newRow("de") << QLocale(QLocale::German) << german;
0083     QTest::newRow("de_DE") << QLocale(QStringLiteral("de_DE")) << german;
0084     QTest::newRow("de_DE@bayern") << QLocale(QStringLiteral("de_DE@bayern")) << german;
0085     QTest::newRow("de@bayern") << QLocale(QStringLiteral("de@bayern")) << german;
0086     QTest::newRow("de@freiburg") << QLocale(QStringLiteral("de@freiburg")) << QStringLiteral("Mein Anwendungsle");
0087     // For CH we have a special translation
0088     QTest::newRow("de_CH") << QLocale(QLocale::German, QLocale::Switzerland) << swiss;
0089     QTest::newRow("de_CH@bern") << QLocale(QStringLiteral("de_CH@bern")) << swiss;
0090     // Austria should fall back to "de"
0091     QTest::newRow("de_AT") << QLocale(QLocale::German, QLocale::Austria) << german;
0092     QTest::newRow("de_AT@tirol") << QLocale(QStringLiteral("de_AT@tirol")) << german;
0093     // no translation for French
0094     QTest::newRow("fr") << QLocale(QLocale::French) << QStringLiteral("My Application");
0095 }
0096 
0097 void KDesktopFileTest::testReadLocalized()
0098 {
0099     QTemporaryFile file(QStringLiteral("testReadLocalizedXXXXXX.desktop"));
0100     QVERIFY(file.open());
0101     const QString fileName = file.fileName();
0102     QTextStream ts(&file);
0103     ts << "[Desktop Entry]\n"
0104           "Type=Application\n"
0105           "Name=My Application\n"
0106           "Name[de]=Meine Anwendung\n"
0107           "Name[de@freiburg]=Mein Anwendungsle\n"
0108           "Name[de_CH]=Mein Anwendungsli\n"
0109           "Icon=foo\n"
0110           "\n";
0111     file.close();
0112     QVERIFY(QFile::exists(fileName));
0113     QVERIFY(KDesktopFile::isDesktopFile(fileName));
0114 
0115     DefaultLocale defaultLocale;
0116 
0117     QFETCH(QLocale, locale);
0118     QLocale::setDefault(locale);
0119     KDesktopFile df(fileName);
0120 
0121     QEXPECT_FAIL("de@freiburg", "QLocale doesn't support modifiers", Continue);
0122     QTEST(df.readName(), "translation");
0123 }
0124 
0125 void KDesktopFileTest::testSuccessfulTryExec()
0126 {
0127     QTemporaryFile file;
0128     QVERIFY(file.open());
0129     const QString fileName = file.fileName();
0130     QTextStream ts(&file);
0131     ts << "[Desktop Entry]\n"
0132           "TryExec=whoami\n"
0133           "\n";
0134     file.close();
0135     QVERIFY(QFile::exists(fileName));
0136     KDesktopFile df(fileName);
0137     QCOMPARE(df.tryExec(), true);
0138 }
0139 
0140 void KDesktopFileTest::testUnsuccessfulTryExec()
0141 {
0142     QTemporaryFile file;
0143     QVERIFY(file.open());
0144     const QString fileName = file.fileName();
0145     QTextStream ts(&file);
0146     ts << "[Desktop Entry]\n"
0147           "TryExec=/does/not/exist\n"
0148           "\n";
0149     file.close();
0150     QVERIFY(QFile::exists(fileName));
0151     KDesktopFile df(fileName);
0152     QCOMPARE(df.tryExec(), false);
0153 }
0154 
0155 void KDesktopFileTest::testActionGroup()
0156 {
0157     QTemporaryFile file;
0158     QVERIFY(file.open());
0159     const QString fileName = file.fileName();
0160     QTextStream ts(&file);
0161     ts << "[Desktop Entry]\n"
0162           // make sure escaping of ';' using "\;" works
0163           "Actions=encrypt;semi\\;colon;decrypt;\n"
0164           "[Desktop Action encrypt]\n"
0165           "Name=Encrypt file\n"
0166           "[Desktop Action decrypt]\n"
0167           "Name=Decrypt file\n"
0168           // no escaping needed in group header
0169           "[Desktop Action semi;colon]\n"
0170           "Name=With semicolon\n"
0171           "\n";
0172     file.close();
0173     QVERIFY(QFile::exists(fileName));
0174     KDesktopFile df(fileName);
0175     QCOMPARE(df.readType(), QString());
0176     QCOMPARE(df.fileName(), QFileInfo(fileName).canonicalFilePath());
0177     QCOMPARE(df.readActions(), (QStringList{QStringLiteral("encrypt"), QStringLiteral("semi;colon"), QStringLiteral("decrypt")}));
0178     QCOMPARE(df.hasActionGroup(QStringLiteral("encrypt")), true);
0179     QCOMPARE(df.hasActionGroup(QStringLiteral("semi;colon")), true);
0180     QCOMPARE(df.hasActionGroup(QStringLiteral("decrypt")), true);
0181     QCOMPARE(df.hasActionGroup(QStringLiteral("doesnotexist")), false);
0182     KConfigGroup cg = df.actionGroup(QStringLiteral("encrypt"));
0183     QVERIFY(cg.hasKey("Name"));
0184     QCOMPARE(cg.readEntry("Name"), QStringLiteral("Encrypt file"));
0185     cg = df.actionGroup(QStringLiteral("decrypt"));
0186     QVERIFY(cg.hasKey("Name"));
0187     QCOMPARE(cg.readEntry("Name"), QStringLiteral("Decrypt file"));
0188     cg = df.actionGroup(QStringLiteral("semi;colon"));
0189     QVERIFY(cg.hasKey("Name"));
0190     QCOMPARE(cg.readEntry("Name"), QStringLiteral("With semicolon"));
0191 }
0192 
0193 void KDesktopFileTest::testIsAuthorizedDesktopFile()
0194 {
0195     QTemporaryFile file(QStringLiteral("testAuthXXXXXX.desktop"));
0196     QVERIFY(file.open());
0197     const QString fileName = file.fileName();
0198     QTextStream ts(&file);
0199     ts << "[Desktop Entry]\n"
0200           "Type=Application\n"
0201           "Name=My Application\n"
0202           "Exec=kfoo\n"
0203           "\n";
0204     file.close();
0205     QVERIFY(QFile::exists(fileName));
0206 
0207 #if defined(Q_OS_UNIX)
0208     // Try to fix test failing in docker running as root
0209     const QFileInfo entryInfo(fileName);
0210     if (entryInfo.ownerId() == 0) {
0211         // try to find a valid user/group combination
0212         for (int i = 1; i < 100; ++i) {
0213             if (chown(fileName.toLocal8Bit().constData(), i, i) == 0) {
0214                 break;
0215             }
0216         }
0217         const QFileInfo entryInfo1(fileName);
0218         if (entryInfo1.ownerId() == 0) {
0219             QEXPECT_FAIL("", "Running test as root and could not find a non root user to change the ownership of the file too", Continue);
0220         }
0221     }
0222 #endif
0223 
0224     QVERIFY(!KDesktopFile::isAuthorizedDesktopFile(fileName));
0225 
0226     const QString installedFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("/kservices5/http_cache_cleaner.desktop"));
0227     if (!installedFile.isEmpty()) {
0228         QVERIFY(KDesktopFile::isAuthorizedDesktopFile(installedFile));
0229     } else {
0230         qWarning("Skipping test for http_cache_cleaner.desktop, not found. kio not installed?");
0231     }
0232 
0233     const QString autostartFile = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("autostart/plasma-desktop.desktop"));
0234     if (!autostartFile.isEmpty()) {
0235         QVERIFY(KDesktopFile::isAuthorizedDesktopFile(autostartFile));
0236     } else {
0237         qWarning("Skipping test for plasma-desktop.desktop, not found. kde-workspace not installed?");
0238     }
0239 }
0240 
0241 void KDesktopFileTest::testTryExecWithAuthorizeAction()
0242 {
0243     {
0244         QTemporaryFile file(QStringLiteral("testAuthActionXXXXXX.desktop"));
0245         QVERIFY(file.open());
0246         const QString fileName = file.fileName();
0247         QTextStream ts(&file);
0248         ts << "[Desktop Entry]\n"
0249               "Type=Application\n"
0250               "Name=My Application\n"
0251               "Exec=kfoo\n"
0252               "TryExec=";
0253 #ifdef Q_OS_WIN
0254         ts << "cmd\n";
0255 #else
0256         ts << "bash\n";
0257 #endif
0258         ts << "X-KDE-AuthorizeAction=someAction"
0259               "\n";
0260         file.close();
0261 
0262         KDesktopFile desktopFile(fileName);
0263         QVERIFY(desktopFile.tryExec());
0264     }
0265     {
0266         QTemporaryFile file(QStringLiteral("testAuthActionXXXXXX.desktop"));
0267         QVERIFY(file.open());
0268         const QString fileName = file.fileName();
0269         QTextStream ts(&file);
0270         ts << "[Desktop Entry]\n"
0271               "Type=Application\n"
0272               "Name=My Application\n"
0273               "Exec=kfoo\n"
0274               "TryExec=bash\n"
0275               "X-KDE-AuthorizeAction=someBlockedAction"
0276               "\n";
0277         file.close();
0278 
0279         KDesktopFile desktopFile(fileName);
0280         QVERIFY(!desktopFile.tryExec());
0281     }
0282 }
0283 
0284 void KDesktopFileTest::testLocateLocal_data()
0285 {
0286     const QString systemConfigLocation = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation).constLast();
0287     const QString writableConfigLocation = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
0288     const QString systemDataLocation = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).constLast();
0289     const QString writableDataLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
0290 
0291     QTest::addColumn<QString>("path");
0292     QTest::addColumn<QString>("result");
0293 
0294     QTest::newRow("configLocation, system-wide") << systemConfigLocation + QLatin1String{"/test.desktop"}
0295                                                  << writableConfigLocation + QLatin1String{"/test.desktop"};
0296     QTest::newRow("autostart, system-wide") << systemConfigLocation + QLatin1String{"/autostart/test.desktop"}
0297                                             << writableConfigLocation + QLatin1String{"/autostart/test.desktop"};
0298     QTest::newRow("dataLocation, system-wide") << systemDataLocation + QLatin1String{"/test.desktop"} << writableDataLocation + QLatin1String{"/test.desktop"};
0299     QTest::newRow("applications, system-wide") << systemDataLocation + QLatin1String{"/applications/test.desktop"}
0300                                                << writableDataLocation + QLatin1String{"/applications/test.desktop"};
0301     QTest::newRow("desktop-directories, system-wide") << systemDataLocation + QLatin1String{"/desktop-directories/test.directory"}
0302                                                       << writableDataLocation + QLatin1String{"/desktop-directories/test.directory"};
0303     QTest::newRow("configLocation, writable") << writableConfigLocation + QLatin1String{"/test.desktop"}
0304                                               << writableConfigLocation + QLatin1String{"/test.desktop"};
0305     QTest::newRow("autostart, writable") << writableConfigLocation + QLatin1String{"/autostart/test.desktop"}
0306                                          << writableConfigLocation + QLatin1String{"/autostart/test.desktop"};
0307     QTest::newRow("dataLocation, writable") << writableDataLocation + QLatin1String{"/test.desktop"} << writableDataLocation + QLatin1String{"/test.desktop"};
0308     QTest::newRow("applications, writable") << writableDataLocation + QLatin1String{"/applications/test.desktop"}
0309                                             << writableDataLocation + QLatin1String{"/applications/test.desktop"};
0310     QTest::newRow("desktop-directories, writable") << writableDataLocation + QLatin1String{"/desktop-directories/test.directory"}
0311                                                    << writableDataLocation + QLatin1String{"/desktop-directories/test.directory"};
0312     QTest::newRow("unknown location") << QStringLiteral("/test.desktop") << writableDataLocation + QLatin1String{"/test.desktop"};
0313 }
0314 
0315 void KDesktopFileTest::testLocateLocal()
0316 {
0317     QFETCH(QString, path);
0318     QFETCH(QString, result);
0319 
0320     QCOMPARE(KDesktopFile::locateLocal(path), result);
0321 }
0322 
0323 #include "moc_kdesktopfiletest.cpp"