From 4038960c82ce26eb56f2e1e6dfce863e244f5b6c Mon Sep 17 00:00:00 2001 From: Christoph Cullmann Date: Fri, 10 May 2024 21:49:56 +0200 Subject: [PATCH] include duplication check works now on all platforms without fdupes installed --- autotests/CMakeLists.txt | 4 -- autotests/dupetest.cpp | 94 ---------------------------------------- src/tools/qrcAlias.cpp | 49 +++++++++++++++++---- 3 files changed, 40 insertions(+), 107 deletions(-) delete mode 100644 autotests/dupetest.cpp diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 92eb1a67..d5471276 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -12,10 +12,6 @@ if(BUILD_TESTING) TEST_NAME "newline" LINK_LIBRARIES Qt6::Test ) - ecm_add_test(dupetest.cpp - TEST_NAME "dupe" - LINK_LIBRARIES Qt6::Test - ) ecm_add_test(scalabletest.cpp TEST_NAME "scalable" LINK_LIBRARIES Qt6::Test diff --git a/autotests/dupetest.cpp b/autotests/dupetest.cpp deleted file mode 100644 index 4bb6ab78..00000000 --- a/autotests/dupetest.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - Copyright 2016 Harald Sitter - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) version 3, or any - later version accepted by the membership of KDE e.V. (or its - successor approved by the membership of KDE e.V.), which shall - act as a proxy defined in Section 6 of version 3 of the license. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. If not, see . -*/ - -#include -#include -#include -#include - -#include "testhelpers.h" - -class DupeTest : public QObject -{ - Q_OBJECT - - QStringList splitOnUnescapedSpace(const QString &line) - { - QStringList ret; - const int lineLength = line.length(); - int start = 0; - for (int pos = 0; pos < lineLength; ++pos) { - const QChar ch = line[pos]; - if (ch == QLatin1Char('\\')) { - ++pos; - continue; - } else if (ch == QLatin1Char(' ')) { - ret.append(line.mid(start, pos - start)); - start = pos + 1; - } - } - if (start < lineLength) { - ret.append(line.mid(start)); - } - return ret; - } - - void readLines(QProcess &proc) - { - QString line; - while (proc.canReadLine() || proc.waitForReadyRead()) { - line = QString::fromUtf8(proc.readLine()); - failListContent(splitOnUnescapedSpace(line.simplified()), QStringLiteral("The following files are duplicates but not links:\n")); - } - } - - void dupesForDirectory(const QString &path) - { - const QString exec = QStandardPaths::findExecutable(QStringLiteral("fdupes")); - QVERIFY(!exec.isEmpty()); - QProcess proc; - proc.setProgram(exec); - proc.setArguments(QStringList() << QStringLiteral("--recurse") << QStringLiteral("--sameline") << QStringLiteral("--nohidden") << path); - proc.start(); - proc.waitForStarted(); - readLines(proc); - } - -private Q_SLOTS: - void test_duplicates() - { - if (QStandardPaths::findExecutable(QStringLiteral("fdupes")).isEmpty()) { -#ifdef Q_OS_UNIX - // Fail and skip. This is a fairly relevant test, so it not running is a warning really. - QFAIL("this test needs the fdupes binary (1.51+) to run"); -#else - // On Windows let's just skip it - QSKIP("this test needs the fdupes binary (1.51+) to run"); -#endif - } - for (auto dir : ICON_DIRS) { - dupesForDirectory(PROJECT_SOURCE_DIR + QStringLiteral("/") + dir); - } - } -}; - -QTEST_GUILESS_MAIN(DupeTest) - -#include "dupetest.moc" diff --git a/src/tools/qrcAlias.cpp b/src/tools/qrcAlias.cpp index 9ca61933..3869c1c1 100644 --- a/src/tools/qrcAlias.cpp +++ b/src/tools/qrcAlias.cpp @@ -12,24 +12,39 @@ #include #include #include +#include #include #include #include #include +/** + * Check if this file is a duplicate of an other on, dies then. + * @param fileName file to check + */ +static void checkForDuplicates(const QString &fileName) +{ + // get full content for dupe checking + QFile in(fileName); + if (!in.open(QIODevice::ReadOnly)) { + qFatal() << "failed to open" << in.fileName() << "for XML validation"; + } + const auto fullContent = in.readAll(); + + // see if we did have this content already and die + static QHash contentToFileName; + if (const auto it = contentToFileName.find(fullContent); it != contentToFileName.end()) { + qFatal() << "file" << fileName << "is a duplicate of file" << it.value(); + } + contentToFileName.insert(fullContent, fileName); +} + /** * Validate the XML, dies on errors. * @param fileName file to validate */ static void validateXml(const QString &fileName) { - // do checks just once, if we encounter this multiple times because of aliasing - static QSet seenFiles; - if (seenFiles.contains(fileName)) { - return; - } - seenFiles.insert(fileName); - // read once and bail out on errors QFile in(fileName); if (!in.open(QIODevice::ReadOnly)) { @@ -96,6 +111,9 @@ static void generateQRCAndCheckInputs(const QStringList &indirs, const QString & out.write("\n"); out.write("\n"); + // loop over the inputs, remember if we do look at generated stuff for checks + bool generatedIcons = false; + QSet checkedFiles; for (const auto &indir : indirs) { // go to input dir to have proper relative paths if (!QDir::setCurrent(indir)) { @@ -127,14 +145,27 @@ static void generateQRCAndCheckInputs(const QStringList &indirs, const QString & fullPath = QFileInfo(aliasLink).absoluteFilePath(); } - // validate it as XML if it is an SVG - if (fullPath.endsWith(QLatin1String(".svg"))) { + // do some checks for SVGs + // do checks just once, if we encounter this multiple times because of aliasing + if (fullPath.endsWith(QLatin1String(".svg")) && !checkedFiles.contains(fullPath)) { + // fill our guard + checkedFiles.insert(fullPath); + + // validate it as XML if it is an SVG validateXml(fullPath); + + // do duplicate check for non-generated icons + if (!generatedIcons) { + checkForDuplicates(fullPath); + } } // write the one alias to file entry out.write(QStringLiteral(" %2\n").arg(file, fullPath).toUtf8()); } + + // starting with the second directory we look at generated icons + generatedIcons = true; } out.write("\n");