File indexing completed on 2024-09-15 06:32: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"