File indexing completed on 2024-04-28 03:53:13

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