diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -14,11 +14,11 @@ TEST_NAME "newline" LINK_LIBRARIES Qt5::Test ) - ecm_add_test(dupetest.cpp + ecm_add_test(dupetest.cpp kiconloaderdummy.cpp TEST_NAME "dupe" LINK_LIBRARIES Qt5::Test ) - ecm_add_test(scalabletest.cpp + ecm_add_test(scalabletest.cpp kiconloaderdummy.cpp TEST_NAME "scalable" LINK_LIBRARIES Qt5::Test ) diff --git a/autotests/dupetest.cpp b/autotests/dupetest.cpp --- a/autotests/dupetest.cpp +++ b/autotests/dupetest.cpp @@ -22,6 +22,7 @@ #include #include "testhelpers.h" +#include "kiconloaderdummy.h" class DupeTest : public QObject { @@ -88,6 +89,54 @@ dupesForDirectory(PROJECT_SOURCE_DIR + QStringLiteral("/") + dir); } } + + void test_duplicateNames() + { + for (auto dir : ICON_DIRS) { + auto themeDir = PROJECT_SOURCE_DIR + QStringLiteral("/") + dir; + + QHash>> contextHash; + + QSettings config(themeDir + "/index.theme", QSettings::IniFormat); + auto keys = config.allKeys(); + config.beginGroup("Icon Theme"); + auto directoryPaths = config.value("Directories", QString()).toStringList(); + config.endGroup(); + QVERIFY(!directoryPaths.isEmpty()); + for (auto directoryPath : directoryPaths) { + config.beginGroup(directoryPath); + QVERIFY2(keys.contains(directoryPath+"/Size"),QString("The theme %1 has an entry 'Directories' which specifies '%2' as directory, but there's no" + " have no associated entry '%2/Size'").arg(themeDir + "/index.theme", directoryPath).toLatin1()); + auto dir = QSharedPointer::create(config, themeDir); + config.endGroup(); + contextHash[dir->context].append(dir); + } + + QHash>>> filesByName; + for (auto it = contextHash.constBegin(), itEnd = contextHash.constEnd(); it != itEnd; ++it) { + for (const auto &dir: *it) { + for (const auto &file: dir->allIcons()) { + filesByName[file.completeBaseName()][dir->context] << dir; + } + } + } + + for (auto it = filesByName.constBegin(), itEnd = filesByName.constEnd(); it != itEnd; ++it) { + if (it.value().count() > 1) { + const auto alts = it.value(); + qDebug() << "duplicated name" << it.key() << alts.keys().count(); + for(auto itAlts = alts.cbegin(), itAltsEnd = alts.cend(); itAlts != itAltsEnd; ++itAlts) { + QStringList paths; + for(auto alt : itAlts.value()) { + paths << alt->path; + } + qDebug() << "in" << itAlts.key() << paths.count() << paths; + } + } + } + } + + } }; QTEST_GUILESS_MAIN(DupeTest) diff --git a/autotests/kiconloaderdummy.h b/autotests/kiconloaderdummy.h new file mode 100644 --- /dev/null +++ b/autotests/kiconloaderdummy.h @@ -0,0 +1,140 @@ +#ifndef KICONLOADERDUMMY_H +#define KICONLOADERDUMMY_H + +#include +#include +#include +#include +#include +#include + +// lift a bit of code from KIconLoader to get the unit test running without tier 3 libraries +class KIconLoaderDummy : public QObject +{ +Q_OBJECT +public: + enum Context { + Any, + Action, + Application, + Device, + FileSystem, + MimeType, + Animation, + Category, + Emblem, + Emote, + International, + Place, + StatusIcon + }; + Q_ENUM(Context) + enum Type { + Fixed, + Scalable, + Threshold + }; + Q_ENUM(Type) +}; + + +/** + * Represents icon directory to conduct simple icon lookup within. + */ +class Dir +{ +public: + Dir(const QSettings &cg, const QString &themeDir_) + : + themeDir(themeDir_) + , path(cg.group()) + , size(cg.value("Size", 0).toInt()) + , contextString(cg.value("Context", QString()).toString()) + , context(parseContext(contextString)) + , type(parseType(cg.value("Type", QString("Threshold")).toString())) + { + QVERIFY2(!contextString.isEmpty(), + QString("Missing 'Context' key in file %1, config group '[%2]'").arg(cg.fileName(), cg.group()).toLatin1()); + QVERIFY2(context != -1, + QString("Don't know how to handle 'Context=%1' in file %2, config group '[%3]'").arg(contextString, cg.fileName(), cg.group()).toLatin1()); + } + + static QMetaEnum findEnum(const char *name) + { + auto mo = KIconLoaderDummy::staticMetaObject; + for (int i = 0; i < mo.enumeratorCount(); ++i) { + auto enumerator = mo.enumerator(i); + if (strcmp(enumerator.name(), name) == 0) { + return KIconLoaderDummy::staticMetaObject.enumerator(i); + } + } + Q_ASSERT(false); // failed to resolve enum + return QMetaEnum(); + } + + static QMetaEnum typeEnum() + { + static auto e = findEnum("Type"); + return e; + } + + static KIconLoaderDummy::Context parseContext(const QString &string) + { + // Can't use QMetaEnum as the enum names are singular, the entry values are plural though. + static QHash hash { + { QStringLiteral("Actions"), KIconLoaderDummy::Action }, + { QStringLiteral("Animations"), KIconLoaderDummy::Animation }, + { QStringLiteral("Applications"), KIconLoaderDummy::Application }, + { QStringLiteral("Categories"), KIconLoaderDummy::Category }, + { QStringLiteral("Devices"), KIconLoaderDummy::Device }, + { QStringLiteral("Emblems"), KIconLoaderDummy::Emblem }, + { QStringLiteral("Emotes"), KIconLoaderDummy::Emote }, + { QStringLiteral("MimeTypes"), KIconLoaderDummy::MimeType }, + { QStringLiteral("Places"), KIconLoaderDummy::Place }, + { QStringLiteral("Status"), KIconLoaderDummy::StatusIcon }, + }; + const auto value = hash.value(string, -1); + return static_cast(value); // the caller will check that it wasn't -1 + } + + static KIconLoaderDummy::Type parseType(const QString &string) + { + bool ok; + auto v = (KIconLoaderDummy::Type)typeEnum().keyToValue(string.toLatin1(), &ok); + Q_ASSERT(ok); + return v; + } + + /** + * @returns list of all icon's fileinfo (first level only, selected types + * only) + */ + QList allIcons() + { + QList icons; + auto iconDir = QString("%1/%2").arg(themeDir).arg(path); + QDirIterator it(iconDir); + while (it.hasNext()) { + it.next(); + auto suffix = it.fileInfo().suffix(); + if (suffix != "svg" && suffix != "svgz" && suffix != "png") { + continue; // Probably not an icon. + } + icons << it.fileInfo(); + } + return icons; + } + + QString themeDir; + QString path; + uint size; + QString contextString; + KIconLoaderDummy::Context context; + KIconLoaderDummy::Type type; +}; + +// Declare so we can put them into the QTest data table. +Q_DECLARE_METATYPE(KIconLoaderDummy::Context) +Q_DECLARE_METATYPE(QSharedPointer) + +#endif diff --git a/autotests/kiconloaderdummy.cpp b/autotests/kiconloaderdummy.cpp new file mode 100644 --- /dev/null +++ b/autotests/kiconloaderdummy.cpp @@ -0,0 +1 @@ +#include "kiconloaderdummy.h" diff --git a/autotests/scalabletest.cpp b/autotests/scalabletest.cpp --- a/autotests/scalabletest.cpp +++ b/autotests/scalabletest.cpp @@ -25,134 +25,7 @@ #include // parsing the ini files as desktop files #include "testhelpers.h" -// lift a bit of code from KIconLoader to get the unit test running without tier 3 libraries -class KIconLoaderDummy : public QObject -{ -Q_OBJECT -public: - enum Context { - Any, - Action, - Application, - Device, - FileSystem, - MimeType, - Animation, - Category, - Emblem, - Emote, - International, - Place, - StatusIcon - }; - Q_ENUM(Context) - enum Type { - Fixed, - Scalable, - Threshold - }; - Q_ENUM(Type) -}; - - -/** - * Represents icon directory to conduct simple icon lookup within. - */ -class Dir -{ -public: - Dir(const QSettings &cg, const QString &themeDir_) - : - themeDir(themeDir_) - , path(cg.group()) - , size(cg.value("Size", 0).toInt()) - , contextString(cg.value("Context", QString()).toString()) - , context(parseContext(contextString)) - , type(parseType(cg.value("Type", QString("Threshold")).toString())) - { - QVERIFY2(!contextString.isEmpty(), - QString("Missing 'Context' key in file %1, config group '[%2]'").arg(cg.fileName(), cg.group()).toLatin1()); - QVERIFY2(context != -1, - QString("Don't know how to handle 'Context=%1' in file %2, config group '[%3]'").arg(contextString, cg.fileName(), cg.group()).toLatin1()); - } - - static QMetaEnum findEnum(const char *name) - { - auto mo = KIconLoaderDummy::staticMetaObject; - for (int i = 0; i < mo.enumeratorCount(); ++i) { - auto enumerator = mo.enumerator(i); - if (strcmp(enumerator.name(), name) == 0) { - return KIconLoaderDummy::staticMetaObject.enumerator(i); - } - } - Q_ASSERT(false); // failed to resolve enum - return QMetaEnum(); - } - - static QMetaEnum typeEnum() - { - static auto e = findEnum("Type"); - return e; - } - - static KIconLoaderDummy::Context parseContext(const QString &string) - { - // Can't use QMetaEnum as the enum names are singular, the entry values are plural though. - static QHash hash { - { QStringLiteral("Actions"), KIconLoaderDummy::Action }, - { QStringLiteral("Animations"), KIconLoaderDummy::Animation }, - { QStringLiteral("Applications"), KIconLoaderDummy::Application }, - { QStringLiteral("Categories"), KIconLoaderDummy::Category }, - { QStringLiteral("Devices"), KIconLoaderDummy::Device }, - { QStringLiteral("Emblems"), KIconLoaderDummy::Emblem }, - { QStringLiteral("Emotes"), KIconLoaderDummy::Emote }, - { QStringLiteral("MimeTypes"), KIconLoaderDummy::MimeType }, - { QStringLiteral("Places"), KIconLoaderDummy::Place }, - { QStringLiteral("Status"), KIconLoaderDummy::StatusIcon }, - }; - const auto value = hash.value(string, -1); - return static_cast(value); // the caller will check that it wasn't -1 - } - - static KIconLoaderDummy::Type parseType(const QString &string) - { - bool ok; - auto v = (KIconLoaderDummy::Type)typeEnum().keyToValue(string.toLatin1(), &ok); - Q_ASSERT(ok); - return v; - } - - /** - * @returns list of all icon's fileinfo (first level only, selected types - * only) - */ - QList allIcons() - { - QList icons; - auto iconDir = QString("%1/%2").arg(themeDir).arg(path); - QDirIterator it(iconDir); - while (it.hasNext()) { - it.next(); - auto suffix = it.fileInfo().suffix(); - if (suffix != "svg" && suffix != "svgz" && suffix != "png") { - continue; // Probably not an icon. - } - icons << it.fileInfo(); - } - return icons; - } - - QString themeDir; - QString path; - uint size; - QString contextString; - KIconLoaderDummy::Context context; - KIconLoaderDummy::Type type; -}; - -// Declare so we can put them into the QTest data table. -Q_DECLARE_METATYPE(KIconLoaderDummy::Context) -Q_DECLARE_METATYPE(QSharedPointer) +#include "kiconloaderdummy.h" class ScalableTest : public QObject {