include duplication check
works now on all platforms without fdupes installed
This commit is contained in:
parent
b971378872
commit
4038960c82
@ -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
|
||||
|
||||
@ -1,94 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 Harald Sitter <sitter@kde.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QStandardPaths>
|
||||
#include <QTest>
|
||||
|
||||
#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"
|
||||
@ -12,24 +12,39 @@
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QHash>
|
||||
#include <QRegularExpression>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
/**
|
||||
* 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<QByteArray, QString> 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<QString> 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("<!DOCTYPE RCC><RCC version=\"1.0\">\n");
|
||||
out.write("<qresource>\n");
|
||||
|
||||
// loop over the inputs, remember if we do look at generated stuff for checks
|
||||
bool generatedIcons = false;
|
||||
QSet<QString> 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();
|
||||
}
|
||||
|
||||
// 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
|
||||
if (fullPath.endsWith(QLatin1String(".svg"))) {
|
||||
validateXml(fullPath);
|
||||
|
||||
// do duplicate check for non-generated icons
|
||||
if (!generatedIcons) {
|
||||
checkForDuplicates(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
// write the one alias to file entry
|
||||
out.write(QStringLiteral(" <file alias=\"%1\">%2</file>\n").arg(file, fullPath).toUtf8());
|
||||
}
|
||||
|
||||
// starting with the second directory we look at generated icons
|
||||
generatedIcons = true;
|
||||
}
|
||||
|
||||
out.write("</qresource>\n");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user