File indexing completed on 2024-04-14 03:54:33

0001 /*
0002     SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org>
0003     SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "kservicetest.h"
0009 
0010 #include "setupxdgdirs.h"
0011 
0012 #include <locale.h>
0013 
0014 #include <QTest>
0015 
0016 #include <../src/services/kserviceutil_p.h> // for KServiceUtilPrivate
0017 #include <KConfig>
0018 #include <KConfigGroup>
0019 #include <KDesktopFile>
0020 #include <kapplicationtrader.h>
0021 #include <kbuildsycoca_p.h>
0022 #include <ksycoca.h>
0023 
0024 #include <KPluginMetaData>
0025 #include <kservicegroup.h>
0026 
0027 #include <QFile>
0028 #include <QSignalSpy>
0029 #include <QStandardPaths>
0030 #include <QThread>
0031 
0032 #include <QDebug>
0033 #include <QLoggingCategory>
0034 #include <QMimeDatabase>
0035 
0036 QTEST_MAIN(KServiceTest)
0037 
0038 extern KSERVICE_EXPORT int ksycoca_ms_between_checks;
0039 
0040 static void eraseProfiles()
0041 {
0042     QString profilerc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String{"/profilerc"};
0043     if (!profilerc.isEmpty()) {
0044         QFile::remove(profilerc);
0045     }
0046 
0047     profilerc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String{"/servicetype_profilerc"};
0048     if (!profilerc.isEmpty()) {
0049         QFile::remove(profilerc);
0050     }
0051 }
0052 
0053 void KServiceTest::initTestCase()
0054 {
0055     // Set up a layer in the bin dir so ksycoca finds the Application servicetypes
0056     setupXdgDirs();
0057     QStandardPaths::setTestModeEnabled(true);
0058 
0059     // A non-C locale is necessary for some tests.
0060     // This locale must have the following properties:
0061     //   - some character other than dot as decimal separator
0062     // If it cannot be set, locale-dependent tests are skipped.
0063     setlocale(LC_ALL, "fr_FR.utf8");
0064     QLocale::setDefault(QLocale(QStringLiteral("fr_FR")));
0065     m_hasNonCLocale = (setlocale(LC_ALL, nullptr) == QByteArray("fr_FR.utf8"));
0066     if (!m_hasNonCLocale) {
0067         qDebug() << "Setting locale to fr_FR.utf8 failed";
0068     }
0069 
0070     eraseProfiles();
0071 
0072     if (!KSycoca::isAvailable()) {
0073         runKBuildSycoca();
0074     }
0075 
0076     // Create some fake services for the tests below, and ensure they are in ksycoca.
0077 
0078     bool mustUpdateKSycoca = false;
0079 
0080     // org.kde.deleteme.desktop: deleted and recreated by testDeletingService, don't use in other tests
0081     const QString deleteMeApp = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1String("/org.kde.deleteme.desktop");
0082     if (!QFile::exists(deleteMeApp)) {
0083         QVERIFY(QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)));
0084         const QString src = QFINDTESTDATA("org.kde.deleteme.desktop");
0085         QVERIFY(!src.isEmpty());
0086         QVERIFY2(QFile::copy(src, deleteMeApp), qPrintable(deleteMeApp));
0087         qDebug() << "Created" << deleteMeApp;
0088         mustUpdateKSycoca = true;
0089     }
0090 
0091     // org.kde.faketestapp.desktop
0092     const QString testApp = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1String("/org.kde.faketestapp.desktop");
0093     if (!QFile::exists(testApp)) {
0094         QVERIFY(QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)));
0095         const QString src = QFINDTESTDATA("org.kde.faketestapp.desktop");
0096         QVERIFY(!src.isEmpty());
0097         QVERIFY2(QFile::copy(src, testApp), qPrintable(testApp));
0098         qDebug() << "Created" << testApp;
0099         mustUpdateKSycoca = true;
0100     }
0101 
0102     // otherfakeapp.desktop
0103     const QString otherTestApp = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1String("/org.kde.otherfakeapp.desktop");
0104     if (!QFile::exists(otherTestApp)) {
0105         QVERIFY(QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)));
0106         const QString src = QFINDTESTDATA("org.kde.otherfakeapp.desktop");
0107         QVERIFY(!src.isEmpty());
0108         QVERIFY2(QFile::copy(src, otherTestApp), qPrintable(otherTestApp));
0109         qDebug() << "Created" << otherTestApp;
0110         mustUpdateKSycoca = true;
0111     }
0112     // testnames.desktop
0113     const QString namesTestApp = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1String("/org.kde.testnames.desktop");
0114     if (!QFile::exists(namesTestApp)) {
0115         QVERIFY(QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)));
0116         const QString src = QFINDTESTDATA("org.kde.testnames.desktop");
0117         QVERIFY(!src.isEmpty());
0118         QVERIFY2(QFile::copy(src, namesTestApp), qPrintable(namesTestApp));
0119         qDebug() << "Created" << namesTestApp;
0120         mustUpdateKSycoca = true;
0121     }
0122 
0123     if (mustUpdateKSycoca) {
0124         // Update ksycoca in ~/.qttest after creating the above
0125         runKBuildSycoca(true);
0126     }
0127     QVERIFY(KService::serviceByDesktopName(QStringLiteral("org.kde.faketestapp")));
0128     QVERIFY(KService::serviceByDesktopName(QStringLiteral("org.kde.otherfakeapp")));
0129     QVERIFY(KService::serviceByDesktopName(QStringLiteral("org.kde.testnames")));
0130 }
0131 
0132 void KServiceTest::runKBuildSycoca(bool noincremental)
0133 {
0134     QSignalSpy spy(KSycoca::self(), &KSycoca::databaseChanged);
0135 
0136     KBuildSycoca builder;
0137     QVERIFY(builder.recreate(!noincremental));
0138     if (spy.isEmpty()) {
0139         qDebug() << "waiting for signal";
0140         QVERIFY(spy.wait(10000));
0141         qDebug() << "got signal";
0142     }
0143 }
0144 
0145 void KServiceTest::cleanupTestCase()
0146 {
0147     KBuildSycoca builder;
0148     builder.recreate();
0149 }
0150 
0151 void KServiceTest::testByName()
0152 {
0153     if (!KSycoca::isAvailable()) {
0154         QSKIP("ksycoca not available");
0155     }
0156 
0157     const QString filePath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("applications/org.kde.faketestapp.desktop"));
0158     KService::Ptr myService = KService::serviceByDesktopPath(filePath);
0159     QVERIFY(myService);
0160     QCOMPARE(myService->name(), QStringLiteral("Konsole"));
0161 }
0162 
0163 void KServiceTest::testConstructorFullPath()
0164 {
0165     const QString filePath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("applications/org.kde.faketestapp.desktop"));
0166     QVERIFY(QFile::exists(filePath));
0167     KService service(filePath);
0168     QVERIFY(service.isValid());
0169     QCOMPARE(service.name(), QStringLiteral("Konsole"));
0170 }
0171 
0172 void KServiceTest::testConstructorKDesktopFile() // as happens inside kbuildsycoca.cpp
0173 {
0174     const QString filePath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("applications/org.kde.faketestapp.desktop"));
0175     KDesktopFile desktopFile(filePath);
0176     QCOMPARE(KService(&desktopFile, filePath).name(), QStringLiteral("Konsole"));
0177 }
0178 
0179 void KServiceTest::testCopyConstructor()
0180 {
0181     const QString filePath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("applications/org.kde.faketestapp.desktop"));
0182     QVERIFY(QFile::exists(filePath));
0183     KDesktopFile desktopFile(filePath);
0184     // Test making a copy of a KService that will go out of scope
0185     KService::Ptr service;
0186     {
0187         KService origService(&desktopFile);
0188         service = new KService(origService);
0189     }
0190     QVERIFY(service->isValid());
0191     QCOMPARE(service->name(), QStringLiteral("Konsole"));
0192 }
0193 
0194 void KServiceTest::testCopyInvalidService()
0195 {
0196     KService::Ptr service;
0197     {
0198         KService origService{QString()}; // this still sets a d_ptr, so no problem;
0199         QVERIFY(!origService.isValid());
0200         service = new KService(origService);
0201     }
0202     QVERIFY(!service->isValid());
0203 }
0204 
0205 void KServiceTest::testProperty()
0206 {
0207     ksycoca_ms_between_checks = 0;
0208 
0209     // Let's try creating a desktop file and ensuring it's noticed by the timestamp check
0210     QTest::qWait(1000);
0211     QString fakeAppPath = KService::newServicePath(false, QStringLiteral("org.kde.foo"));
0212     if (!QFile::exists(fakeAppPath)) {
0213         KDesktopFile file(fakeAppPath);
0214         KConfigGroup group = file.desktopGroup();
0215         group.writeEntry("Name", "Foo");
0216         group.writeEntry("Type", "Application");
0217         group.writeEntry("X-Flatpak-RenamedFrom", "foo;bar;");
0218         group.writeEntry("Exec", "bla");
0219         group.writeEntry("X-GNOME-UsesNotifications", true);
0220         qDebug() << "created" << fakeAppPath;
0221     }
0222 
0223     KService::Ptr fakeApp = KService::serviceByDesktopName(QStringLiteral("org.kde.foo"));
0224     QVERIFY(fakeApp);
0225     QStringList expectedRename{QStringLiteral("foo"), QStringLiteral("bar")};
0226     QCOMPARE(fakeApp->property<QStringList>(QStringLiteral("X-Flatpak-RenamedFrom")), expectedRename);
0227     QCOMPARE(fakeApp->property<bool>(QStringLiteral("X-GNOME-UsesNotifications")), true);
0228     QVERIFY(!fakeApp->property<QString>(QStringLiteral("Name")).isEmpty());
0229     QVERIFY(fakeApp->property<QString>(QStringLiteral("Name[fr]")).isEmpty());
0230 
0231     // Restore value
0232     ksycoca_ms_between_checks = 1500;
0233 }
0234 
0235 void KServiceTest::testAllServices()
0236 {
0237     if (!KSycoca::isAvailable()) {
0238         QSKIP("ksycoca not available");
0239     }
0240     const KService::List lst = KService::allServices();
0241     QVERIFY(!lst.isEmpty());
0242     bool foundTestApp = false;
0243 
0244     for (const KService::Ptr &service : lst) {
0245         QVERIFY(service->isType(KST_KService));
0246 
0247         const QString name = service->name();
0248         const QString entryPath = service->entryPath();
0249         if (entryPath.contains(QLatin1String{"fake"})) {
0250             qDebug() << name << "entryPath=" << entryPath << "menuId=" << service->menuId();
0251         }
0252         QVERIFY(!name.isEmpty());
0253         QVERIFY(!entryPath.isEmpty());
0254 
0255         KService::Ptr lookedupService = KService::serviceByDesktopPath(entryPath);
0256         QVERIFY(lookedupService); // not null
0257         QCOMPARE(lookedupService->entryPath(), entryPath);
0258 
0259         if (service->isApplication()) {
0260             const QString menuId = service->menuId();
0261             if (menuId.isEmpty()) {
0262                 qWarning("%s has an empty menuId!", qPrintable(entryPath));
0263             } else if (menuId == QLatin1String{"org.kde.faketestapp.desktop"}) {
0264                 foundTestApp = true;
0265             }
0266             QVERIFY(!menuId.isEmpty());
0267             lookedupService = KService::serviceByMenuId(menuId);
0268             QVERIFY(lookedupService); // not null
0269             QCOMPARE(lookedupService->menuId(), menuId);
0270         }
0271     }
0272     QVERIFY(foundTestApp);
0273 }
0274 
0275 void KServiceTest::testByStorageId()
0276 {
0277     if (!KSycoca::isAvailable()) {
0278         QSKIP("ksycoca not available");
0279     }
0280     QVERIFY(!QStandardPaths::locate(QStandardPaths::ApplicationsLocation, QStringLiteral("org.kde.faketestapp.desktop")).isEmpty());
0281     QVERIFY(KService::serviceByMenuId(QStringLiteral("org.kde.faketestapp.desktop")));
0282     QVERIFY(!KService::serviceByMenuId(QStringLiteral("org.kde.faketestapp"))); // doesn't work, extension mandatory
0283     QVERIFY(!KService::serviceByMenuId(QStringLiteral("faketestapp.desktop"))); // doesn't work, full filename mandatory
0284     QVERIFY(KService::serviceByStorageId(QStringLiteral("org.kde.faketestapp.desktop")));
0285     QVERIFY(KService::serviceByStorageId(QStringLiteral("org.kde.faketestapp")));
0286 
0287     QVERIFY(KService::serviceByDesktopName(QStringLiteral("org.kde.faketestapp")));
0288     QCOMPARE(KService::serviceByDesktopName(QStringLiteral("org.kde.faketestapp"))->menuId(), QStringLiteral("org.kde.faketestapp.desktop"));
0289 }
0290 
0291 void KServiceTest::testSubseqConstraints()
0292 {
0293     auto test = [](const char *pattern, const char *text, bool sensitive) {
0294         return KApplicationTrader::isSubsequence(QString::fromLatin1(pattern), QString::fromLatin1(text), sensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
0295     };
0296 
0297     // Case Sensitive
0298     QVERIFY2(!test("", "", 1), "both empty");
0299     QVERIFY2(!test("", "something", 1), "empty pattern");
0300     QVERIFY2(!test("something", "", 1), "empty text");
0301     QVERIFY2(test("lngfile", "somereallylongfile", 1), "match ending");
0302     QVERIFY2(test("somelong", "somereallylongfile", 1), "match beginning");
0303     QVERIFY2(test("reallylong", "somereallylongfile", 1), "match middle");
0304     QVERIFY2(test("across", "a 23 c @#! r o01 o 5 s_s", 1), "match across");
0305     QVERIFY2(!test("nocigar", "soclosebutnociga", 1), "close but no match");
0306     QVERIFY2(!test("god", "dog", 1), "incorrect letter order");
0307     QVERIFY2(!test("mismatch", "mIsMaTcH", 1), "case sensitive mismatch");
0308 
0309     // Case insensitive
0310     QVERIFY2(test("mismatch", "mIsMaTcH", 0), "case insensitive match");
0311     QVERIFY2(test("tryhards", "Try Your Hardest", 0), "uppercase text");
0312     QVERIFY2(test("TRYHARDS", "try your hardest", 0), "uppercase pattern");
0313 }
0314 
0315 void KServiceTest::testActionsAndDataStream()
0316 {
0317     KService::Ptr service = KService::serviceByStorageId(QStringLiteral("org.kde.faketestapp.desktop"));
0318     QVERIFY(service);
0319     QVERIFY(service->property<QString>(QStringLiteral("Name[fr]")).isEmpty());
0320     const QList<KServiceAction> actions = service->actions();
0321     QCOMPARE(actions.count(), 2); // NewWindow, NewTab
0322     const KServiceAction newTabAction = actions.at(1);
0323     QCOMPARE(newTabAction.name(), QStringLiteral("NewTab"));
0324     QCOMPARE(newTabAction.exec(), QStringLiteral("konsole --new-tab"));
0325     QCOMPARE(newTabAction.icon(), QStringLiteral("tab-new"));
0326     QCOMPARE(newTabAction.noDisplay(), false);
0327     QVERIFY(!newTabAction.isSeparator());
0328     QCOMPARE(newTabAction.service()->name(), service->name());
0329 }
0330 
0331 void KServiceTest::testServiceGroups()
0332 {
0333     KServiceGroup::Ptr root = KServiceGroup::root();
0334     QVERIFY(root);
0335     qDebug() << root->groupEntries().count();
0336 
0337     KServiceGroup::Ptr group = root;
0338     QVERIFY(group);
0339     const KServiceGroup::List list = group->entries(true, // sorted
0340                                                     true, // exclude no display entries,
0341                                                     false, // allow separators
0342                                                     true); // sort by generic name
0343 
0344     qDebug() << list.count();
0345     for (KServiceGroup::SPtr s : list) {
0346         qDebug() << s->name() << s->entryPath();
0347     }
0348 
0349     // No unit test here yet, but at least this can be valgrinded for errors.
0350 }
0351 
0352 void KServiceTest::testDeletingService()
0353 {
0354     // workaround unexplained inotify issue (in CI only...)
0355     QTest::qWait(1000);
0356 
0357     const QString serviceName = QStringLiteral("org.kde.deleteme");
0358     KService::Ptr fakeService = KService::serviceByDesktopName(serviceName);
0359     QVERIFY(fakeService); // see initTestCase; it should be found.
0360 
0361     // Test deleting a service
0362     const QString servPath = fakeService->locateLocal();
0363     QVERIFY(QFile::exists(servPath));
0364     QFile::remove(servPath);
0365     runKBuildSycoca();
0366     ksycoca_ms_between_checks = 0; // need it to check the ksycoca mtime
0367     QVERIFY(!KService::serviceByDesktopName(serviceName)); // not in ksycoca anymore
0368 
0369     // Restore value
0370     ksycoca_ms_between_checks = 1500;
0371 
0372     QVERIFY(fakeService); // the whole point of refcounting is that this KService instance is still valid.
0373     QVERIFY(!QFile::exists(servPath));
0374 
0375     // Recreate it, for future tests
0376     const QString deleteMeApp = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + QLatin1String("/org.kde.deleteme.desktop");
0377     const QString src = QFINDTESTDATA("org.kde.deleteme.desktop");
0378     QVERIFY2(QFile::copy(src, deleteMeApp), qPrintable(deleteMeApp));
0379 
0380     runKBuildSycoca();
0381 
0382     if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
0383         m_sycocaUpdateDone.ref();
0384     }
0385 }
0386 
0387 #include <QFutureSynchronizer>
0388 #include <QThreadPool>
0389 #include <QtConcurrentRun>
0390 
0391 // Testing for concurrent access to ksycoca from multiple threads
0392 // It's especially interesting to run this test as ./kservicetest testThreads
0393 // so that even the ksycoca initialization is happening from N threads at the same time.
0394 // Use valgrind --tool=helgrind to see the race conditions.
0395 
0396 void KServiceTest::testReaderThreads()
0397 {
0398     QThreadPool::globalInstance()->setMaxThreadCount(10);
0399     QFutureSynchronizer<void> sync;
0400     sync.addFuture(QtConcurrent::run(&KServiceTest::testAllServices, this));
0401     sync.addFuture(QtConcurrent::run(&KServiceTest::testAllServices, this));
0402     sync.addFuture(QtConcurrent::run(&KServiceTest::testAllServices, this));
0403     sync.addFuture(QtConcurrent::run(&KServiceTest::testAllServices, this));
0404     sync.addFuture(QtConcurrent::run(&KServiceTest::testAllServices, this));
0405     sync.waitForFinished();
0406     QThreadPool::globalInstance()->setMaxThreadCount(1); // delete those threads
0407 }
0408 
0409 void KServiceTest::testThreads()
0410 {
0411     QThreadPool::globalInstance()->setMaxThreadCount(10);
0412     QFutureSynchronizer<void> sync;
0413     sync.addFuture(QtConcurrent::run(&KServiceTest::testAllServices, this));
0414     sync.addFuture(QtConcurrent::run(&KServiceTest::testDeletingService, this));
0415 
0416     // process events (DBus, inotify...), until we get all expected signals
0417     QTRY_COMPARE_WITH_TIMEOUT(m_sycocaUpdateDone.loadRelaxed(), 1, 15000); // not using a bool, just to silence helgrind
0418     qDebug() << "Joining all threads";
0419     sync.waitForFinished();
0420 }
0421 
0422 void KServiceTest::testCompleteBaseName()
0423 {
0424     // dots in filename before .desktop extension:
0425     QCOMPARE(KServiceUtilPrivate::completeBaseName(QStringLiteral("/home/x/.local/share/applications/org.kde.fakeapp.desktop")),
0426              QStringLiteral("org.kde.fakeapp"));
0427 }
0428 
0429 void KServiceTest::testEntryPathToName()
0430 {
0431     QCOMPARE(KService(QStringLiteral("c.desktop")).name(), QStringLiteral("c"));
0432     QCOMPARE(KService(QStringLiteral("a.b.c.desktop")).name(), QStringLiteral("a.b.c")); // dots in filename before .desktop extension
0433     QCOMPARE(KService(QStringLiteral("/hallo/a.b.c.desktop")).name(), QStringLiteral("a.b.c"));
0434 }
0435 
0436 void KServiceTest::testAliasFor()
0437 {
0438     if (!KSycoca::isAvailable()) {
0439         QSKIP("ksycoca not available");
0440     }
0441     KService::Ptr testapp = KService::serviceByDesktopName(QStringLiteral("org.kde.faketestapp"));
0442     QVERIFY(testapp);
0443     QCOMPARE(testapp->aliasFor(), QStringLiteral("org.kde.okular"));
0444 }
0445 
0446 void KServiceTest::testMimeType()
0447 {
0448     if (!KSycoca::isAvailable()) {
0449         QSKIP("ksycoca not available");
0450     }
0451 
0452     KService::Ptr testapp = KService::serviceByDesktopName(QStringLiteral("org.kde.otherfakeapp"));
0453     QVERIFY(testapp);
0454     QCOMPARE(testapp->mimeTypes(), {QStringLiteral("application/pdf")});
0455 }
0456 
0457 void KServiceTest::testProtocols()
0458 {
0459     if (!KSycoca::isAvailable()) {
0460         QSKIP("ksycoca not available");
0461     }
0462 
0463     KService::Ptr testapp = KService::serviceByDesktopName(QStringLiteral("org.kde.otherfakeapp"));
0464     QVERIFY(testapp);
0465     QStringList expectedProtocols{QStringLiteral("http"), QStringLiteral("tel")};
0466     QCOMPARE(testapp->supportedProtocols(), expectedProtocols);
0467 }
0468 
0469 void KServiceTest::testServiceActionService()
0470 {
0471     if (!KSycoca::isAvailable()) {
0472         QSKIP("ksycoca not available");
0473     }
0474 
0475     const QString filePath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("applications/org.kde.faketestapp.desktop"));
0476     QVERIFY(QFile::exists(filePath));
0477     KService service(filePath);
0478     QVERIFY(service.isValid());
0479 
0480     const KServiceAction action = service.actions().first();
0481     QCOMPARE(action.service()->property<bool>(QStringLiteral("DBusActivatable")), true);
0482     QCOMPARE(action.service()->actions().size(), 2);
0483 }
0484 
0485 void KServiceTest::testUntranslatedNames()
0486 {
0487     const QString name = QStringLiteral("Name");
0488     const QString genericName = QStringLiteral("GenericName");
0489     QLatin1String translationPostfix(" trans");
0490 
0491     KService::Ptr app = KService::serviceByDesktopName(QStringLiteral("org.kde.testnames"));
0492     QVERIFY(app);
0493     QVERIFY(app->isValid());
0494     QCOMPARE(app->untranslatedName(), name);
0495     QCOMPARE(app->untranslatedGenericName(), genericName);
0496     QCOMPARE(app->name(), name + translationPostfix);
0497     QCOMPARE(app->genericName(), genericName + translationPostfix);
0498     // Property access
0499     QCOMPARE(app->property<QString>(QStringLiteral("UntranslatedName")), name);
0500     QCOMPARE(app->property<QString>(QStringLiteral("UntranslatedGenericName")), genericName);
0501 }
0502 
0503 void KServiceTest::testStartupNotify()
0504 {
0505     {
0506         QString fakeAppPath = KService::newServicePath(false, QStringLiteral("org.kde.startupnotify1"));
0507         KDesktopFile file(fakeAppPath);
0508         KConfigGroup group = file.desktopGroup();
0509         group.writeEntry("Name", "Foo");
0510         group.writeEntry("Type", "Application");
0511         group.writeEntry("StartupNotify", true);
0512         group.sync();
0513 
0514         KService fakeApp(fakeAppPath);
0515         QVERIFY(fakeApp.isValid());
0516         QVERIFY(fakeApp.startupNotify().value());
0517     }
0518 
0519     {
0520         QString fakeAppPath = KService::newServicePath(false, QStringLiteral("org.kde.startupnotify2"));
0521         KDesktopFile file(fakeAppPath);
0522         KConfigGroup group = file.desktopGroup();
0523         group.writeEntry("Name", "Foo");
0524         group.writeEntry("Type", "Application");
0525         group.writeEntry("StartupNotify", false);
0526         group.sync();
0527 
0528         KService fakeApp(fakeAppPath);
0529         QVERIFY(fakeApp.isValid());
0530         QVERIFY(!fakeApp.startupNotify().value());
0531     }
0532 
0533     {
0534         QString fakeAppPath = KService::newServicePath(false, QStringLiteral("org.kde.startupnotify1"));
0535         KDesktopFile file(fakeAppPath);
0536         KConfigGroup group = file.desktopGroup();
0537         group.writeEntry("Name", "Foo");
0538         group.writeEntry("Type", "Application");
0539         group.writeEntry("X-KDE-StartupNotify", true);
0540         group.sync();
0541 
0542         KService fakeApp(fakeAppPath);
0543         QVERIFY(fakeApp.isValid());
0544         QVERIFY(fakeApp.startupNotify().value());
0545     }
0546 
0547     {
0548         QString fakeAppPath = KService::newServicePath(false, QStringLiteral("org.kde.startupnotify2"));
0549         KDesktopFile file(fakeAppPath);
0550         KConfigGroup group = file.desktopGroup();
0551         group.writeEntry("Name", "Foo");
0552         group.writeEntry("Type", "Application");
0553         group.writeEntry("X-KDE-StartupNotify", false);
0554         group.sync();
0555 
0556         KService fakeApp(fakeAppPath);
0557         QVERIFY(fakeApp.isValid());
0558         QVERIFY(!fakeApp.startupNotify().value());
0559     }
0560 
0561     {
0562         QString fakeAppPath = KService::newServicePath(false, QStringLiteral("org.kde.startupnotify3"));
0563         KDesktopFile file(fakeAppPath);
0564         KConfigGroup group = file.desktopGroup();
0565         group.writeEntry("Name", "Foo");
0566         group.writeEntry("Type", "Application");
0567         group.sync();
0568 
0569         KService fakeApp(fakeAppPath);
0570         QVERIFY(fakeApp.isValid());
0571         QVERIFY(!fakeApp.startupNotify().has_value());
0572     }
0573 }
0574 
0575 #include "moc_kservicetest.cpp"