File indexing completed on 2024-10-06 06:40:35

0001 /*
0002     SPDX-FileCopyrightText: 2016 David Rosca <nowrep@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <QStandardPaths>
0008 #include <QTest>
0009 
0010 #include <KConfigGroup>
0011 #include <KIconEngine>
0012 #include <KIconLoader>
0013 #include <KSharedConfig>
0014 
0015 extern KICONTHEMES_EXPORT int kiconloader_ms_between_checks;
0016 
0017 class KIconEngine_UnitTest : public QObject
0018 {
0019     Q_OBJECT
0020 
0021 private Q_SLOTS:
0022     void initTestCase()
0023     {
0024         QStandardPaths::setTestModeEnabled(true);
0025 
0026         // Remove icon cache
0027         const QString cacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QStringLiteral("/icon-cache.kcache");
0028         QFile::remove(cacheFile);
0029 
0030         KConfigGroup cg(KSharedConfig::openConfig(), "Icons");
0031         cg.writeEntry("Theme", "oxygen");
0032         cg.sync();
0033 
0034         QDir testDataDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
0035         testIconsDir = QDir(testDataDir.absoluteFilePath(QStringLiteral("icons")));
0036 
0037         // we will be recursively deleting these, so a sanity check is in order
0038         QVERIFY(testIconsDir.absolutePath().contains(QLatin1String("qttest")));
0039 
0040         testIconsDir.removeRecursively();
0041 
0042         // set up a minimal Oxygen icon theme, in case it is not installed
0043         QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/apps")));
0044         QVERIFY(QFile::copy(QStringLiteral(":/oxygen.theme"), testIconsDir.filePath(QStringLiteral("oxygen/index.theme"))));
0045         QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/apps/kde.png"))));
0046         QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/apps/org.kde.testapp.png"))));
0047         QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/actions"))); // we need the dir to exist since KIconThemes caches mDirs
0048 
0049         // Clear SHM cache
0050         KIconLoader::global()->reconfigure(QString());
0051     }
0052 
0053     void testValidIconName()
0054     {
0055         QIcon icon(new KIconEngine(QStringLiteral("kde"), KIconLoader::global()));
0056         QVERIFY(!icon.isNull());
0057         QVERIFY(!icon.name().isEmpty());
0058     }
0059 
0060     void testInvalidIconName()
0061     {
0062         QIcon icon(new KIconEngine(QStringLiteral("invalid-icon-name"), KIconLoader::global()));
0063         QVERIFY(icon.isNull());
0064         QVERIFY2(icon.name().isEmpty(), qPrintable(icon.name()));
0065     }
0066 
0067     void testFallbackIconName()
0068     {
0069         QIcon icon(new KIconEngine(QStringLiteral("kde-specific-icon"), KIconLoader::global()));
0070         QVERIFY(!icon.isNull());
0071         QCOMPARE(icon.name(), QStringLiteral("kde"));
0072 
0073         QIcon icon2(new KIconEngine(QStringLiteral("org.kde.testapp-specific-icon"), KIconLoader::global()));
0074         QVERIFY(!icon2.isNull());
0075         QCOMPARE(icon2.name(), QStringLiteral("org.kde.testapp"));
0076     }
0077 
0078     void testUnknownIconNotCached() // QIcon version of the test in kiconloader_unittest.cpp
0079     {
0080         // This is a test to ensure that "unknown" icons are cached as unknown
0081         // for performance reasons, but after a while they'll be looked up again
0082         // so that newly installed icons can be used without a reboot.
0083 
0084         kiconloader_ms_between_checks = 500000;
0085 
0086         QString actionIconsSubdir = QStringLiteral("oxygen/22x22/actions");
0087         QVERIFY(testIconsDir.mkpath(actionIconsSubdir));
0088         QString actionIconsDir = testIconsDir.filePath(actionIconsSubdir);
0089 
0090         QString nonExistingIconName = QStringLiteral("asvdfg_fhqwhgds");
0091         QString newIconPath = actionIconsDir + QLatin1String("/") + nonExistingIconName + QLatin1String(".png");
0092         QFile::remove(newIconPath);
0093 
0094         // Find a non-existent icon
0095         QIcon icon(new KIconEngine(nonExistingIconName, KIconLoader::global()));
0096         QVERIFY(icon.isNull());
0097         QVERIFY(icon.name().isEmpty());
0098 
0099         // Install the existing icon by copying.
0100         QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), newIconPath));
0101 
0102         // Attempt to find the icon again, the cache will still be used for now.
0103         QIcon icon2(new KIconEngine(nonExistingIconName, KIconLoader::global()));
0104         QVERIFY(icon2.isNull());
0105         QVERIFY(icon2.name().isEmpty());
0106 
0107         // Force a recheck to happen on next lookup
0108         kiconloader_ms_between_checks = 0;
0109 
0110         // Verify the icon can now be found.
0111         QIcon nowExistingIcon(new KIconEngine(nonExistingIconName, KIconLoader::global()));
0112         QVERIFY(!nowExistingIcon.isNull());
0113         QCOMPARE(nowExistingIcon.name(), nonExistingIconName);
0114 
0115         // And verify again, this time with the cache
0116         kiconloader_ms_between_checks = 50000;
0117         QIcon icon3(new KIconEngine(nonExistingIconName, KIconLoader::global()));
0118         QVERIFY(!icon3.isNull());
0119         QCOMPARE(icon3.name(), nonExistingIconName);
0120     }
0121 
0122     void testCenterIcon()
0123     {
0124         QIcon icon(new KIconEngine(QStringLiteral("kde"), KIconLoader::global()));
0125         QVERIFY(!icon.isNull());
0126 
0127         // "kde" icon is actually "test-22x22.png", so this is original icon image
0128         const QImage image = icon.pixmap(22, 22).toImage();
0129 
0130         // center vertically
0131         QVERIFY(icon.pixmap(22, 26).toImage().copy(0, 2, 22, 22) == image);
0132 
0133         // center horizontally
0134         QVERIFY(icon.pixmap(26, 22).toImage().copy(2, 0, 22, 22) == image);
0135     }
0136 
0137     void testNonSquareSvg()
0138     {
0139         QIcon icon(new KIconEngine(QStringLiteral(":/nonsquare.svg"), KIconLoader::global()));
0140         QVERIFY(!icon.isNull());
0141 
0142         // verify we get the content fully fitted in when asking for the right aspect ratio
0143         const QImage image = icon.pixmap(40, 20).toImage();
0144         QCOMPARE(image.pixelColor(0, 0), QColor(255, 0, 0));
0145         QCOMPARE(image.pixelColor(19, 9), QColor(255, 0, 0));
0146         QCOMPARE(image.pixelColor(39, 0), QColor(0, 255, 0));
0147         QCOMPARE(image.pixelColor(20, 9), QColor(0, 255, 0));
0148         QCOMPARE(image.pixelColor(0, 19), QColor(0, 0, 255));
0149         QCOMPARE(image.pixelColor(19, 10), QColor(0, 0, 255));
0150         QCOMPARE(image.pixelColor(39, 19), QColor(255, 255, 0));
0151         QCOMPARE(image.pixelColor(20, 10), QColor(255, 255, 0));
0152 
0153         // and now with a wrong aspect ratio
0154         QCOMPARE(icon.pixmap(40, 40).toImage().convertToFormat(image.format()).copy(0, 10, 40, 20), image);
0155     }
0156 
0157 private:
0158     QDir testIconsDir;
0159 };
0160 
0161 QTEST_MAIN(KIconEngine_UnitTest)
0162 
0163 #include "kiconengine_unittest.moc"