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