File indexing completed on 2024-09-29 09:28:08
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2008 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include <kiconloader.h> 0009 0010 #include <QDir> 0011 #include <QRegularExpression> 0012 #include <QStandardPaths> 0013 #include <QTest> 0014 0015 #include <KPixmapSequence> 0016 0017 #include <KConfigGroup> 0018 #include <KSharedConfig> 0019 0020 extern KICONTHEMES_EXPORT void uintToHex(uint32_t colorData, QChar *buffer); 0021 0022 class KIconLoader_UnitTest : public QObject 0023 { 0024 Q_OBJECT 0025 public: 0026 KIconLoader_UnitTest() 0027 : testSizes({12, 22, 32, 42, 82, 132, 243}) 0028 { 0029 } 0030 0031 private: 0032 QDir testDataDir; 0033 QDir testIconsDir; 0034 QString appName; 0035 QDir appDataDir; 0036 const QVector<int> testSizes; 0037 0038 private Q_SLOTS: 0039 void initTestCase() 0040 { 0041 QStandardPaths::setTestModeEnabled(true); 0042 0043 const QStringList genericIconsFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("mime/generic-icons")); 0044 QVERIFY(!genericIconsFiles.isEmpty()); // KIconLoader relies on fallbacks to generic icons (e.g. x-office-document), which comes from a shared-mime-info 0045 // file. Make sure it's installed! 0046 0047 KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); 0048 cg.writeEntry("Theme", "breeze"); 0049 cg.sync(); 0050 0051 testDataDir = QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); 0052 testIconsDir = QDir(testDataDir.absoluteFilePath(QStringLiteral("icons"))); 0053 0054 appName = QStringLiteral("kiconloader_unittest"); 0055 appDataDir = QDir(testDataDir.absoluteFilePath(appName)); 0056 0057 // we will be recursively deleting these, so a sanity check is in order 0058 QVERIFY(testIconsDir.absolutePath().contains(QLatin1String("qttest"))); 0059 QVERIFY(appDataDir.absolutePath().contains(QLatin1String("qttest"))); 0060 0061 testIconsDir.removeRecursively(); 0062 appDataDir.removeRecursively(); 0063 0064 QVERIFY(appDataDir.mkpath(QStringLiteral("pics"))); 0065 QVERIFY(QFile::copy(QStringLiteral(":/app-image.png"), appDataDir.filePath(QStringLiteral("pics/image1.png")))); 0066 QVERIFY(QFile::copy(QStringLiteral(":/app-image.png"), appDataDir.filePath(QStringLiteral("pics/image2.png")))); 0067 0068 // set up a minimal Oxygen icon theme, in case it is not installed 0069 QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/actions"))); 0070 QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/animations"))); 0071 QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/apps"))); 0072 QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/mimetypes"))); 0073 QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/32x32/apps"))); 0074 QVERIFY(QFile::copy(QStringLiteral(":/oxygen.theme"), testIconsDir.filePath(QStringLiteral("oxygen/index.theme")))); 0075 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/apps/kde.png")))); 0076 QVERIFY(QFile::copy(QStringLiteral(":/anim-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/animations/process-working.png")))); 0077 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/text-plain.png")))); 0078 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/application-octet-stream.png")))); 0079 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/image-x-generic.png")))); 0080 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/video-x-generic.png")))); 0081 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/x-office-document.png")))); 0082 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/audio-x-generic.png")))); 0083 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/unknown.png")))); 0084 QVERIFY(QFile::copy(QStringLiteral(":/test-32x32.png"), testIconsDir.filePath(QStringLiteral("oxygen/32x32/apps/kde.png")))); 0085 0086 // set up a minimal Breeze icon theme, fallback to oxygen 0087 QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/actions"))); 0088 QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/animations"))); 0089 QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/apps"))); 0090 QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/mimetypes"))); 0091 QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/appsNoContext"))); 0092 QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/appsNoType"))); 0093 QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/appsNoContextOrType"))); 0094 0095 const QString breezeThemeFile = testIconsDir.filePath(QStringLiteral("breeze/index.theme")); 0096 QVERIFY(QFile::copy(QStringLiteral(":/breeze.theme"), breezeThemeFile)); 0097 // kde.png is missing, it should fallback to oxygen 0098 // QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/apps/kde.png")))); 0099 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), 0100 testIconsDir.filePath(QStringLiteral("breeze/22x22/appsNoContext/iconindirectorywithoutcontext.png")))); 0101 QVERIFY( 0102 QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/appsNoType/iconindirectorywithouttype.png")))); 0103 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), 0104 testIconsDir.filePath(QStringLiteral("breeze/22x22/appsNoContextOrType/iconindirectorywithoutcontextortype.png")))); 0105 QVERIFY(QFile::copy(QStringLiteral(":/anim-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/animations/process-working.png")))); 0106 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/text-plain.png")))); 0107 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/application-octet-stream.png")))); 0108 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/image-x-generic.png")))); 0109 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/video-x-generic.png")))); 0110 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/x-office-document.png")))); 0111 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/audio-x-generic.png")))); 0112 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/unknown.png")))); 0113 QVERIFY(QFile::copy(QStringLiteral(":/coloredsvgicon.svg"), testIconsDir.filePath(QStringLiteral("breeze/22x22/apps/coloredsvgicon.svg")))); 0114 0115 // prepare some icons for our actions test 0116 // when querying breeze for 'one-two', we expect 0117 // 'one' from breeze instead of oxygen's 'one-two'. 0118 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/actions/one-two.png")))); 0119 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/actions/one.png")))); 0120 0121 QVERIFY(QFile::setPermissions(breezeThemeFile, QFileDevice::ReadOwner | QFileDevice::WriteOwner)); 0122 KConfig configFile(breezeThemeFile); 0123 KConfigGroup iconThemeGroup = configFile.group("Icon Theme"); 0124 QVERIFY(iconThemeGroup.isValid()); 0125 QStringList dirs = iconThemeGroup.readEntry("Directories", QStringList()); 0126 for (int i : testSizes) { 0127 const QString relDir = QStringLiteral("%1x%1/emblems").arg(i); 0128 const QString dir = testIconsDir.filePath(QStringLiteral("breeze/") + relDir); 0129 QVERIFY(QDir().mkpath(dir)); 0130 0131 QPixmap img(i, i); 0132 img.fill(Qt::red); 0133 QVERIFY(img.save(dir + QStringLiteral("/red.png"))); 0134 0135 dirs += relDir; 0136 KConfigGroup dirGroup = configFile.group(relDir); 0137 dirGroup.writeEntry("Size", i); 0138 dirGroup.writeEntry("Context", "Emblems"); 0139 dirGroup.writeEntry("Type", "Fixed"); 0140 } 0141 iconThemeGroup.writeEntry("Directories", dirs); 0142 QVERIFY(configFile.sync()); 0143 } 0144 0145 void cleanupTestCase() 0146 { 0147 if (testIconsDir != QDir()) { 0148 testIconsDir.removeRecursively(); 0149 } 0150 if (appDataDir != QDir()) { 0151 appDataDir.removeRecursively(); 0152 } 0153 } 0154 0155 void init() 0156 { 0157 // Remove icon cache 0158 const QString cacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QStringLiteral("/icon-cache.kcache"); 0159 QFile::remove(cacheFile); 0160 0161 // Clear SHM cache 0162 KIconLoader::global()->reconfigure(QString()); 0163 } 0164 0165 void testUnknownIconNotCached() 0166 { 0167 // This is a test to ensure that "unknown" icons do not pin themselves 0168 // in the icon loader. Or in other words, if an "unknown" icon is 0169 // returned, but the appropriate icon is subsequently installed 0170 // properly, the next request for that icon should return the new icon 0171 // instead of the unknown icon. 0172 0173 QString actionIconsSubdir = QStringLiteral("oxygen/22x22/actions"); 0174 QVERIFY(testIconsDir.mkpath(actionIconsSubdir)); 0175 QString actionIconsDir = testIconsDir.filePath(actionIconsSubdir); 0176 0177 QString nonExistingIconName = QStringLiteral("fhqwhgads_homsar"); 0178 QString newIconPath = actionIconsDir + QLatin1String("/") + nonExistingIconName + QLatin1String(".png"); 0179 QFile::remove(newIconPath); 0180 0181 KIconLoader iconLoader; 0182 0183 // Find a non-existent icon, allowing unknown icon to be returned 0184 QPixmap nonExistingIcon = iconLoader.loadIcon(nonExistingIconName, KIconLoader::Toolbar); 0185 QCOMPARE(nonExistingIcon.isNull(), false); 0186 0187 // Install the existing icon by copying. 0188 QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), newIconPath)); 0189 0190 // Verify the icon can now be found. 0191 QPixmap nowExistingIcon = iconLoader.loadIcon(nonExistingIconName, KIconLoader::Toolbar); 0192 QVERIFY(nowExistingIcon.cacheKey() != nonExistingIcon.cacheKey()); 0193 QCOMPARE(iconLoader.iconPath(nonExistingIconName, KIconLoader::Toolbar), newIconPath); 0194 } 0195 0196 void testLoadIconCanReturnNull() 0197 { 0198 // This is a test for the "canReturnNull" argument of KIconLoader::loadIcon(). 0199 // We try to load an icon that doesn't exist, first with canReturnNull=false (the default) 0200 // then with canReturnNull=true. 0201 KIconLoader iconLoader; 0202 // We expect a warning here... This doesn't work though, due to the extended debug 0203 // QTest::ignoreMessage(QtWarningMsg, "KIconLoader::loadIcon: No such icon \"this-icon-does-not-exist\""); 0204 QPixmap pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16); 0205 QVERIFY(!pix.isNull()); 0206 QCOMPARE(pix.size(), QSize(16, 16)); 0207 // Try it again, to see if the cache interfers 0208 pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16); 0209 QVERIFY(!pix.isNull()); 0210 QCOMPARE(pix.size(), QSize(16, 16)); 0211 // And now set canReturnNull to true 0212 pix = 0213 iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16, KIconLoader::DefaultState, QStringList(), nullptr, true); 0214 QVERIFY(pix.isNull()); 0215 // Try getting the "unknown" icon again, to see if the above call didn't put a null icon into the cache... 0216 pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16); 0217 QVERIFY(!pix.isNull()); 0218 QCOMPARE(pix.size(), QSize(16, 16)); 0219 0220 // Another one, to clear "last" cache 0221 pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist-either"), KIconLoader::Desktop, 16); 0222 QVERIFY(!pix.isNull()); 0223 QCOMPARE(pix.size(), QSize(16, 16)); 0224 0225 // Now load the initial one again - do we get the warning again? 0226 pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16); 0227 QVERIFY(!pix.isNull()); 0228 QCOMPARE(pix.size(), QSize(16, 16)); 0229 0230 pix = iconLoader.loadIcon(QStringLiteral("#crazyname"), KIconLoader::NoGroup, 1600); 0231 QVERIFY(!pix.isNull()); 0232 QCOMPARE(pix.size(), QSize(1600, 1600)); 0233 } 0234 0235 void testAppPicsDir() 0236 { 0237 KIconLoader appIconLoader(appName); 0238 QString iconPath = appIconLoader.iconPath(QStringLiteral("image1"), KIconLoader::User); 0239 QCOMPARE(iconPath, appDataDir.filePath(QStringLiteral("pics/image1.png"))); 0240 QVERIFY(QFile::exists(iconPath)); 0241 0242 // Load it again, to use the "last loaded" cache 0243 QString iconPath2 = appIconLoader.iconPath(QStringLiteral("image1"), KIconLoader::User); 0244 QCOMPARE(iconPath, iconPath2); 0245 // Load something else, to clear the "last loaded" cache 0246 QString iconPathTextEdit = appIconLoader.iconPath(QStringLiteral("image2"), KIconLoader::User); 0247 QCOMPARE(iconPathTextEdit, appDataDir.filePath(QStringLiteral("pics/image2.png"))); 0248 QVERIFY(QFile::exists(iconPathTextEdit)); 0249 // Now load kdialog again, to use the real kiconcache 0250 iconPath2 = appIconLoader.iconPath(QStringLiteral("image1"), KIconLoader::User); 0251 QCOMPARE(iconPath, iconPath2); 0252 } 0253 0254 void testAppPicsDir_KDE_icon() 0255 { 0256 // #### This test is broken; it passes even if appName is set to foobar, because 0257 // QIcon::pixmap returns an unknown icon if it can't find the real icon... 0258 KIconLoader appIconLoader(appName); 0259 // Now using KDE::icon. Separate test so that KIconLoader isn't fully inited. 0260 QIcon icon = KDE::icon(QStringLiteral("image1"), &appIconLoader); 0261 { 0262 QPixmap pix = icon.pixmap(QSize(22, 22)); 0263 QVERIFY(!pix.isNull()); 0264 } 0265 // Qt's implementation of actualSize does not crop to squares, ensure we don't do that either 0266 QCOMPARE(icon.actualSize(QSize(96, 22)), QSize(96, 22)); 0267 QCOMPARE(icon.actualSize(QSize(22, 96)), QSize(22, 96)); 0268 QCOMPARE(icon.actualSize(QSize(22, 16)), QSize(22, 16)); 0269 0270 // Can we ask for a really small size? 0271 { 0272 QPixmap pix8 = icon.pixmap(QSize(8, 8)); 0273 QCOMPARE(pix8.size(), QSize(8, 8)); 0274 } 0275 } 0276 0277 void testLoadMimeTypeIcon_data() 0278 { 0279 QTest::addColumn<QString>("iconName"); 0280 QTest::addColumn<QString>("expectedFileName"); 0281 0282 QTest::newRow("existing icon") << QStringLiteral("text-plain") << QStringLiteral("text-plain.png"); 0283 QTest::newRow("octet-stream icon") << QStringLiteral("application-octet-stream") << QStringLiteral("application-octet-stream.png"); 0284 QTest::newRow("non-existing icon") << QStringLiteral("foo-bar") << QStringLiteral("application-octet-stream.png"); 0285 // Test this again, because now we won't go into the "fast path" of loadMimeTypeIcon anymore. 0286 QTest::newRow("existing icon again") << QStringLiteral("text-plain") << QStringLiteral("text-plain.png"); 0287 QTest::newRow("generic fallback") << QStringLiteral("image-foo-bar") << QStringLiteral("image-x-generic.png"); 0288 QTest::newRow("video generic fallback") << QStringLiteral("video-foo-bar") << QStringLiteral("video-x-generic.png"); 0289 QTest::newRow("image-x-generic itself") << QStringLiteral("image-x-generic") << QStringLiteral("image-x-generic.png"); 0290 QTest::newRow("x-office-document icon") << QStringLiteral("x-office-document") << QStringLiteral("x-office-document.png"); 0291 QTest::newRow("unavailable generic icon") << QStringLiteral("application/x-font-vfont") << QStringLiteral("application-octet-stream.png"); 0292 QTest::newRow("#184852") << QStringLiteral("audio/x-tuxguitar") << QStringLiteral("audio-x-generic.png"); 0293 QTest::newRow("#178847") << QStringLiteral("image/x-compressed-xcf") << QStringLiteral("image-x-generic.png"); 0294 QTest::newRow("mimetype generic icon") << QStringLiteral("application-x-fluid") << QStringLiteral("x-office-document.png"); 0295 } 0296 0297 void testLoadMimeTypeIcon() 0298 { 0299 QFETCH(QString, iconName); 0300 QFETCH(QString, expectedFileName); 0301 KIconLoader iconLoader; 0302 QString path; 0303 QPixmap pix = iconLoader.loadMimeTypeIcon(iconName, KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0304 QVERIFY(!pix.isNull()); 0305 QCOMPARE(path.section(QLatin1Char('/'), -1), expectedFileName); 0306 0307 // do the same test using a global iconloader, so that 0308 // we get into the final return statement, which can only happen 0309 // if d->extraDesktopIconsLoaded becomes true first.... 0310 QString path2; 0311 pix = KIconLoader::global()->loadMimeTypeIcon(iconName, KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path2); 0312 QVERIFY(!pix.isNull()); 0313 QCOMPARE(path2, path); 0314 } 0315 0316 void testHasIcon() 0317 { 0318 // Do everything twice to check code paths that might use a cache 0319 QVERIFY(KIconLoader::global()->hasIcon(QStringLiteral("kde"))); 0320 QVERIFY(KIconLoader::global()->hasIcon(QStringLiteral("kde"))); 0321 KIconLoader iconLoader; 0322 QVERIFY(iconLoader.hasIcon(QStringLiteral("kde"))); 0323 0324 QVERIFY(KIconLoader::global()->hasIcon(QStringLiteral("process-working"))); 0325 QVERIFY(KIconLoader::global()->hasIcon(QStringLiteral("process-working"))); 0326 QVERIFY(!KIconLoader::global()->hasIcon(QStringLiteral("no-such-icon-exists"))); 0327 QVERIFY(!KIconLoader::global()->hasIcon(QStringLiteral("no-such-icon-exists"))); 0328 } 0329 0330 void testIconPath() 0331 { 0332 // Test iconPath with non-existing icon 0333 const QString path = KIconLoader::global()->iconPath(QStringLiteral("nope-no-such-icon"), KIconLoader::Desktop, true /*canReturnNull*/); 0334 QVERIFY2(path.isEmpty(), qPrintable(path)); 0335 0336 const QString unknownPath = KIconLoader::global()->iconPath(QStringLiteral("nope-no-such-icon"), KIconLoader::Desktop, false); 0337 QVERIFY(!unknownPath.isEmpty()); 0338 QVERIFY(QFile::exists(unknownPath)); 0339 } 0340 0341 void testCorrectFallback() 0342 { 0343 // we want to prefer icons from the same theme 0344 0345 // so if we have something like: 0346 /* 0347 oxygen: 0348 one-two 0349 0350 breeze: 0351 one 0352 */ 0353 // and we ask for 'one-two', we expect to see 'one' from breeze instead 0354 // of 'one-two' from oxygen. 0355 QString path; 0356 KIconLoader::global()->loadIcon(QStringLiteral("one-two"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0357 QVERIFY(path.contains("breeze/22x22/actions")); 0358 } 0359 0360 void testPathStore() 0361 { 0362 QString path; 0363 QPixmap pix = KIconLoader::global()->loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 0, KIconLoader::DefaultState, QStringList(), &path); 0364 QVERIFY(!path.isEmpty()); 0365 QVERIFY(QFile::exists(path)); 0366 QVERIFY2(path.contains(QLatin1String("32x32")), qPrintable(path)); 0367 QCOMPARE(pix.size(), QSize(32, 32)); 0368 0369 // Compare with iconPath() 0370 QString path2 = KIconLoader::global()->iconPath(QStringLiteral("kde"), KIconLoader::Desktop); 0371 QCOMPARE(path2, path); 0372 0373 // Now specify a size 0374 pix = KIconLoader::global()->loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0375 QVERIFY(!path.isEmpty()); 0376 QVERIFY(QFile::exists(path)); 0377 QVERIFY2(path.contains(QLatin1String("22x22")), qPrintable(path)); 0378 QCOMPARE(pix.size(), QSize(24, 24)); 0379 0380 QVERIFY(KIconLoader::global()->hasIcon(QStringLiteral("kde"))); 0381 0382 path = QString(); 0383 KIconLoader::global() 0384 ->loadIcon(QStringLiteral("does_not_exist"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path, true /* canReturnNull */); 0385 QVERIFY2(path.isEmpty(), qPrintable(path)); 0386 0387 path = QStringLiteral("some filler to check loadIcon() clears the variable"); 0388 KIconLoader::global() 0389 ->loadIcon(QStringLiteral("does_not_exist"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path, true /* canReturnNull */); 0390 QVERIFY2(path.isEmpty(), qPrintable(path)); 0391 0392 // Test that addAppDir doesn't break loading of icons from the old known paths 0393 KIconLoader loader; 0394 // only addAppDir 0395 loader.addAppDir(QStringLiteral("kiconloader_unittest")); 0396 path = QString(); 0397 loader.loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0398 QVERIFY(!path.isEmpty()); 0399 0400 path = QString(); 0401 loader.loadIcon(QStringLiteral("image1"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0402 QVERIFY(!path.isEmpty()); 0403 0404 // only reconfigure 0405 KIconLoader loader2; 0406 path = QString(); 0407 loader2.reconfigure(QStringLiteral("kiconloader_unittest")); 0408 loader2.loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0409 QVERIFY(!path.isEmpty()); 0410 loader2.loadIcon(QStringLiteral("image1"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0411 QVERIFY(!path.isEmpty()); 0412 0413 // both addAppDir and reconfigure 0414 KIconLoader loader3; 0415 path = QString(); 0416 loader3.addAppDir(QStringLiteral("kiconloader_unittest")); 0417 loader3.reconfigure(QStringLiteral("kiconloader_unittest")); 0418 loader3.loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0419 QVERIFY(!path.isEmpty()); 0420 0421 path = QString(); 0422 loader3.loadIcon(QStringLiteral("image1"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0423 QVERIFY(!path.isEmpty()); 0424 } 0425 0426 void testPathsNoContextType() 0427 { 0428 { 0429 QString path; 0430 KIconLoader::global() 0431 ->loadIcon(QStringLiteral("iconindirectorywithoutcontext"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0432 QVERIFY(path.endsWith(QLatin1String("appsNoContext/iconindirectorywithoutcontext.png"))); 0433 } 0434 { 0435 QString path; 0436 KIconLoader::global() 0437 ->loadIcon(QStringLiteral("iconindirectorywithouttype"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0438 QVERIFY(path.endsWith(QLatin1String("appsNoType/iconindirectorywithouttype.png"))); 0439 } 0440 { 0441 QString path; 0442 KIconLoader::global() 0443 ->loadIcon(QStringLiteral("iconindirectorywithoutcontextortype"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); 0444 QVERIFY(path.endsWith(QLatin1String("appsNoContextOrType/iconindirectorywithoutcontextortype.png"))); 0445 } 0446 } 0447 0448 void testLoadIconNoGroupOrSize() // #246016 0449 { 0450 QPixmap pix = KIconLoader::global()->loadIcon(QStringLiteral("connected"), KIconLoader::NoGroup); 0451 QVERIFY(!pix.isNull()); 0452 } 0453 0454 void testUnknownIcon() 0455 { 0456 QPixmap pix = KIconLoader::unknown(); 0457 QPixmap pix2 = KIconLoader::unknown(); 0458 QCOMPARE(pix.cacheKey(), pix2.cacheKey()); 0459 } 0460 0461 void testLoadPixmapSequence() 0462 { 0463 KPixmapSequence seq = KIconLoader::global()->loadPixmapSequence(QStringLiteral("process-working"), 22); 0464 QVERIFY(seq.isValid()); 0465 } 0466 0467 void testAppropriateSizes() 0468 { 0469 const KIconLoader iconLoader; 0470 const QRegularExpression rx(QStringLiteral("/(\\d+)x\\d+/")); 0471 for (int i = 1; i < testSizes.last() * 1.2; i += 3) { 0472 QString path; 0473 QPixmap pix = iconLoader.loadIcon(QStringLiteral("red"), KIconLoader::Desktop, i, KIconLoader::DefaultState, QStringList(), &path); 0474 QVERIFY(!path.isEmpty()); 0475 QVERIFY(!pix.isNull()); 0476 0477 const QRegularExpressionMatch match = rx.match(path); 0478 QVERIFY(match.isValid()); 0479 0480 const int foundSize = match.captured(1).toInt(); 0481 int ts = testSizes.last(); 0482 for (int w = 0; w < testSizes.size(); w++) { 0483 const int curr = testSizes[w]; 0484 if (curr >= i) { 0485 ts = curr; 0486 break; 0487 } 0488 } 0489 QVERIFY(ts == foundSize); 0490 } 0491 } 0492 0493 void testColoredSvgIcon() 0494 { 0495 QPalette pal = qApp->palette(); 0496 pal.setColor(QPalette::WindowText, QColor(255, 0, 0)); 0497 qApp->setPalette(pal); 0498 QImage img = KIconLoader::global()->loadIcon(QStringLiteral("coloredsvgicon"), KIconLoader::NoGroup).toImage(); 0499 QVERIFY(!img.isNull()); 0500 // Has the image been recolored to red, 0501 // that is the color we wrote in kdeglobals as text color? 0502 QCOMPARE(img.pixel(0, 0), (uint)4294901760); 0503 } 0504 0505 void testUintToHex() 0506 { 0507 // HEX (ARGB format without the #): ff6496c8 0508 QColor testColorNoAlpha(100, 150, 200); 0509 0510 // The ARGB string in which the composed hex value is stored. 0511 QString argbHex(8, Qt::Uninitialized); 0512 0513 // Verify the ARGB hex (ff6496c8) 0514 uintToHex(testColorNoAlpha.rgba(), argbHex.data()); 0515 QCOMPARE(argbHex, QStringLiteral("ff6496c8")); 0516 0517 // HEX (ARGB format without the #): 7b6496c8 0518 QColor testColorWithAlpha(100, 150, 200, 123); 0519 0520 // Test uintToHex to verify its ARGB output. 0521 uintToHex(testColorWithAlpha.rgba(), argbHex.data()); 0522 QCOMPARE(argbHex, QStringLiteral("7b6496c8")); 0523 } 0524 0525 void testQDirSetSearchPaths() 0526 { 0527 // setup search path for testprefix: => we shall find the iconinspecialsearchpath.svg afterwards, see e.g. bug 434451 0528 QDir::setSearchPaths("testprefix", QStringList(":/searchpathdefineddir")); 0529 QPixmap pix = KIconLoader::global()->loadIcon(QStringLiteral("testprefix:iconinspecialsearchpath.svg"), 0530 KIconLoader::NoGroup, 0531 24, 0532 KIconLoader::DefaultState, 0533 QStringList(), 0534 nullptr, 0535 true); 0536 QVERIFY(!pix.isNull()); 0537 } 0538 }; 0539 0540 QTEST_MAIN(KIconLoader_UnitTest) 0541 0542 #include "kiconloader_unittest.moc"