File indexing completed on 2025-01-05 03:58:03

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2021-02-20
0007  * Description : Unit tests for TagsCache class
0008  *
0009  * SPDX-FileCopyrightText: 2021 by David Haslam <dch dot code at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "haariface_utest.h"
0016 
0017 // C++ includes
0018 
0019 #include <set>
0020 #include <iostream>
0021 
0022 // Qt includes
0023 
0024 #include <QString>
0025 #include <QDebug>
0026 #include <QSqlDatabase>
0027 
0028 // Local includes
0029 
0030 #include "digikam_debug.h"
0031 #include "haariface.h"
0032 #include "duplicatesfinder.h"
0033 #include "albumselectors.h"
0034 #include "album.h"
0035 #include "findduplicatesalbumitem.h"
0036 #include "dtestdatadir.h"
0037 #include "dbengineparameters.h"
0038 #include "albummanager.h"
0039 #include "collectionmanager.h"
0040 #include "collectionlocation.h"
0041 #include "facedbaccess.h"
0042 #include "similaritydbaccess.h"
0043 #include "similaritydb.h"
0044 #include "coredbaccess.h"
0045 #include "thumbsdbaccess.h"
0046 #include "scancontroller.h"
0047 
0048 using namespace Digikam;
0049 
0050 typedef QString ImagePath;
0051 
0052 #define ENABLE_TIMEOUT 0
0053 
0054 #define PATHFROMFILEINFO(info) \
0055     QDir(filesPath).relativeFilePath(info.filePath())
0056 
0057 #define START_SEARCHING_DUPLICATES                                                                          \
0058 do                                                                                                          \
0059 {                                                                                                           \
0060     AlbumManager::instance()->clearCurrentAlbums();                                                         \
0061     SimilarityDbAccess().db()->clearImageSimilarity();                                                      \
0062     /* 50% because largerSmaler.png has only 58% similarity */                                              \
0063     DuplicatesFinder* finder = new DuplicatesFinder(searchAlbums, tags, HaarIface::AlbumTagRelation::NoMix, \
0064                         50, 100,                                                                            \
0065                         HaarIface::DuplicatesSearchRestrictions::None,                                      \
0066                         refImageSelMethod, referenceAlbums);                                                \
0067     bool complete = false;                                                                                  \
0068                                                                                                             \
0069     connect(finder, &DuplicatesFinder::signalComplete,                                                      \
0070             [&complete]()                                                                                   \
0071         {                                                                                                   \
0072             complete = true;                                                                                \
0073         }                                                                                                   \
0074     );                                                                                                      \
0075                                                                                                             \
0076     finder->start();                                                                                        \
0077     auto startTime = QDateTime::currentMSecsSinceEpoch();                                                   \
0078                                                                                                             \
0079     while (!complete)                                                                                       \
0080     {                                                                                                       \
0081         QTest::qWait(100);                                                                                  \
0082                                                                                                             \
0083         if (ENABLE_TIMEOUT)                                                                                 \
0084         {                                                                                                   \
0085             QVERIFY(QDateTime::currentMSecsSinceEpoch() - startTime < 1000);                                \
0086         }                                                                                                   \
0087     }                                                                                                       \
0088                                                                                                             \
0089     QTest::qWait(1000); /* Wait until AlbumManager refreshed the salbums */                                 \
0090                                                                                                             \
0091     AlbumList aList = AlbumManager::instance()->allSAlbums();                                               \
0092                                                                                                             \
0093     for (AlbumList::iterator it = aList.begin() ; it != aList.end() ; ++it)                                 \
0094     {                                                                                                       \
0095         SAlbum* salbum = dynamic_cast<SAlbum*>(*it);                                                        \
0096                                                                                                             \
0097         if (salbum)                                                                                         \
0098         {                                                                                                   \
0099             salbum->removeExtraData(this);                                                                  \
0100         }                                                                                                   \
0101     }                                                                                                       \
0102                                                                                                             \
0103     QTreeWidget w;                                                                                          \
0104                                                                                                             \
0105     for (AlbumList::const_iterator it = aList.constBegin() ; it != aList.constEnd() ; ++it)                 \
0106     {                                                                                                       \
0107         SAlbum* const salbum = dynamic_cast<SAlbum*>(*it);                                                  \
0108                                                                                                             \
0109         if (salbum && salbum->isDuplicatesSearch() && !salbum->extraData(this))                             \
0110         {                                                                                                   \
0111             /* Adding item to listView by creating an item and passing listView as parent */                \
0112             FindDuplicatesAlbumItem* const item = new FindDuplicatesAlbumItem(&w, salbum);                  \
0113             salbum->setExtraData(this, item);                                                               \
0114             const auto id   = salbum->title().toLongLong();                                                 \
0115             ItemInfo info(id);                                                                              \
0116             const auto path = QDir(filesPath).relativeFilePath(info.filePath());                            \
0117             const QList<ItemInfo> duplicates = item->duplicatedItems();                                     \
0118                                                                                                             \
0119             if (!references.contains(path))                                                                 \
0120             {                                                                                               \
0121                 references.insert(path, duplicates);                                                        \
0122             }                                                                                               \
0123         }                                                                                                   \
0124     }                                                                                                       \
0125 } while (false);
0126 
0127 HaarIfaceTest::HaarIfaceTest(QObject* const parent)
0128     : QObject(parent)
0129 {
0130     filesPath = DTestDataDir::TestData(QString::fromUtf8("core/tests/database/duplicates"))
0131                    .root().path() + QLatin1Char('/');
0132     qCDebug(DIGIKAM_TESTS_LOG) << "Test Data Dir:" << filesPath;
0133 }
0134 
0135 void HaarIfaceTest::initTestCase()
0136 {
0137     auto dir = QDir(filesPath);
0138     startSqlite(dir);
0139 
0140     // Update collection path, because this is hardcoded
0141 
0142     for (const auto& col: CollectionManager::instance()->allLocations())
0143     {
0144         CollectionManager::instance()->removeLocation(col);
0145     }
0146 
0147     QVERIFY(dir.cd(QStringLiteral("Collection")));
0148 
0149     // The new collection is in the same path as the database, but in the "Collection" subfolder
0150 
0151     const auto collectionPath = dir.absolutePath();
0152     CollectionManager::instance()->addLocation(QUrl::fromLocalFile(collectionPath),
0153                                                QStringLiteral("Collection"));
0154 
0155     ScanController::instance()->completeCollectionScan();
0156     ScanController::instance()->allowToScanDeferredFiles();
0157     AlbumManager::instance()->startScan();
0158 }
0159 
0160 void HaarIfaceTest::cleanupTestCase()
0161 {
0162     stopSql();
0163 }
0164 
0165 void HaarIfaceTest::startSqlite(const QDir& dbDir)
0166 {
0167     qCDebug(DIGIKAM_TESTS_LOG) << "Setup Sqlite Database...";
0168 
0169     if (!QSqlDatabase::isDriverAvailable(DbEngineParameters::SQLiteDatabaseType()))
0170     {
0171         QWARN("Qt SQlite plugin is missing.");
0172         return;
0173     }
0174 
0175     DbEngineParameters params;
0176     params.databaseType = DbEngineParameters::SQLiteDatabaseType();
0177     params.setCoreDatabasePath(dbDir.path() + QLatin1String("/digikam4.db"));
0178     params.setThumbsDatabasePath(dbDir.path() + QLatin1String("/thumbnails-digikam.db"));
0179     params.setFaceDatabasePath(dbDir.path() + QLatin1String("/recognition.db"));
0180     params.setSimilarityDatabasePath(dbDir.path() + QLatin1String("/similarity.db"));
0181     params.legacyAndDefaultChecks();
0182 
0183     // ------------------------------------------------------------------------------------
0184 
0185     qCDebug(DIGIKAM_TESTS_LOG) << "Initializing SQlite database...";
0186     QVERIFY2(AlbumManager::instance()->setDatabase(params, false, filesPath, true),
0187              "Cannot initialize Sqlite database");
0188 
0189     QTest::qWait(3000);
0190 }
0191 
0192 void HaarIfaceTest::stopSql()
0193 {
0194     qCDebug(DIGIKAM_TESTS_LOG) << "Shutting down SQlite database";
0195     ScanController::instance()->shutDown();
0196     AlbumManager::instance()->cleanUp();
0197 
0198     qCDebug(DIGIKAM_TESTS_LOG) << "Cleaning Sqlite database";
0199     CoreDbAccess::cleanUpDatabase();
0200     ThumbsDbAccess::cleanUpDatabase();
0201     FaceDbAccess::cleanUpDatabase();
0202 }
0203 
0204 // Collection/2020/LargerSmaler.png
0205 // Collection/2021/2.png
0206 // Collection/2022/3.png
0207 // Collection/2023/4.png
0208 // Collection/potentialDuplicates/4.png
0209 // Collection/potentialDuplicates/5.png
0210 // Collection/potentialDuplicates/subfolder/2.png
0211 // Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaler.png
0212 
0213 /*!
0214  * \brief HaarIfaceTest::testOriginal
0215  * Original behaviour
0216  */
0217 void HaarIfaceTest::testOriginal()
0218 {
0219     AlbumList all                = AlbumManager::instance()->allPAlbums();
0220     const auto refImageSelMethod = HaarIface::RefImageSelMethod::OlderOrLarger;
0221     AlbumList tags; // empty
0222     AlbumList searchAlbums       = all;
0223     AlbumList referenceAlbums;
0224 
0225     QHash<ImagePath, QList<ItemInfo>> references;
0226     START_SEARCHING_DUPLICATES
0227 
0228     QCOMPARE(references.count(), 3);
0229 
0230     {
0231         QVERIFY(references.contains(QStringLiteral("Collection/2020/LargerSmaller.png"))); // This one is larger
0232         auto duplicates = references.value(QStringLiteral("Collection/2020/LargerSmaller.png"));
0233         QCOMPARE(duplicates.count(), 1);
0234         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0235                  QStringLiteral("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png"));
0236     }
0237 
0238     {
0239         QVERIFY(references.contains(QStringLiteral("Collection/potentialDuplicates/subfolder/2.png"))); // This one is Older
0240         auto duplicates = references.value(QStringLiteral("Collection/potentialDuplicates/subfolder/2.png"));
0241         QCOMPARE(duplicates.count(), 1);
0242         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0243                  QStringLiteral("Collection/2021/2.png"));
0244     }
0245 
0246     {
0247         QVERIFY(references.contains(QStringLiteral("Collection/2023/4.png"))); // exactly same
0248         auto duplicates = references.value(QStringLiteral("Collection/2023/4.png"));
0249         QCOMPARE(duplicates.count(), 1);
0250         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0251                  QStringLiteral("Collection/potentialDuplicates/4.png"));
0252     }
0253 }
0254 
0255 /*!
0256  * \brief HaarIfaceTest::testExcludeRefSelectpotentialDuplicates
0257  * The selected folder shall not be used as reference
0258  */
0259 void HaarIfaceTest::testExcludeRefSelectpotentialDuplicates()
0260 {
0261     const auto refImageSelMethod = HaarIface::RefImageSelMethod::ExcludeFolder;
0262     AlbumList all                = AlbumManager::instance()->allPAlbums();
0263 
0264     AlbumList tags; // empty
0265     AlbumList searchAlbums = all;
0266     AlbumList referenceAlbums;
0267 
0268     for (auto* a: all)
0269     {
0270         const auto& path = static_cast<PAlbum*>(a)->albumPath();
0271 
0272         if (path.startsWith(QStringLiteral("/potentialDuplicates")))
0273         {
0274             // potentialDuplicates and subfolders
0275 
0276             referenceAlbums << a;
0277         }
0278     }
0279 
0280     QHash<ImagePath, QList<ItemInfo>> references;
0281     START_SEARCHING_DUPLICATES
0282 
0283     QCOMPARE(references.count(), 3);
0284 
0285     {
0286         QVERIFY(references.contains(QStringLiteral("Collection/2020/LargerSmaller.png")));
0287         auto duplicates = references.value(QStringLiteral("Collection/2020/LargerSmaller.png"));
0288         QCOMPARE(duplicates.count(), 1);
0289         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0290                  QStringLiteral("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png"));
0291     }
0292 
0293     {
0294         QVERIFY(references.contains(QStringLiteral("Collection/2021/2.png")));
0295         auto duplicates = references.value(QStringLiteral("Collection/2021/2.png"));
0296         QCOMPARE(duplicates.count(), 1);
0297         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0298                  QStringLiteral("Collection/potentialDuplicates/subfolder/2.png"));
0299     }
0300 
0301     {
0302         QVERIFY(references.contains(QStringLiteral("Collection/2023/4.png")));
0303         auto duplicates = references.value(QStringLiteral("Collection/2023/4.png"));
0304         QCOMPARE(duplicates.count(), 1);
0305         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0306                  QStringLiteral("Collection/potentialDuplicates/4.png"));
0307     }
0308 }
0309 
0310 /*!
0311  * \brief HaarIfaceTest::testPreferFolderSelectpotentialDuplicates
0312  * The selected folder is prefered as reference
0313  */
0314 void HaarIfaceTest::testPreferFolderSelectpotentialDuplicates()
0315 {
0316     const auto refImageSelMethod = HaarIface::RefImageSelMethod::PreferFolder;
0317     AlbumList all                = AlbumManager::instance()->allPAlbums();
0318 
0319     AlbumList tags; // empty
0320     AlbumList searchAlbums = all;
0321     AlbumList referenceAlbums;
0322 
0323     for (auto* a: all)
0324     {
0325         const auto& path = static_cast<PAlbum*>(a)->albumPath();
0326 
0327         if (path.startsWith(QStringLiteral("/potentialDuplicates")))
0328         {
0329             // potentialDuplicates and subfolders
0330 
0331             referenceAlbums << a;
0332         }
0333     }
0334 
0335     QHash<ImagePath, QList<ItemInfo>> references;
0336     START_SEARCHING_DUPLICATES;
0337 
0338     QCOMPARE(references.count(), 3);
0339 
0340     {
0341         QVERIFY(references.contains(QStringLiteral("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png")));
0342         auto duplicates = references.value(QStringLiteral("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png"));
0343         QCOMPARE(duplicates.count(), 1);
0344         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)), QStringLiteral("Collection/2020/LargerSmaller.png"));
0345     }
0346 
0347     {
0348         QVERIFY(references.contains(QStringLiteral("Collection/potentialDuplicates/subfolder/2.png")));
0349         auto duplicates = references.value(QStringLiteral("Collection/potentialDuplicates/subfolder/2.png"));
0350         QCOMPARE(duplicates.count(), 1);
0351         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)), QStringLiteral("Collection/2021/2.png"));
0352     }
0353 
0354     {
0355         QVERIFY(references.contains(QStringLiteral("Collection/potentialDuplicates/4.png")));
0356         auto duplicates = references.value(QStringLiteral("Collection/potentialDuplicates/4.png"));
0357         QCOMPARE(duplicates.count(), 1);
0358         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)), QStringLiteral("Collection/2023/4.png"));
0359     }
0360 }
0361 
0362 void HaarIfaceTest::testPreferNewerCreationDate()
0363 {
0364     const auto refImageSelMethod = HaarIface::RefImageSelMethod::NewerCreationDate;
0365     AlbumList all                = AlbumManager::instance()->allPAlbums();
0366 
0367     AlbumList tags; // empty
0368     AlbumList searchAlbums = all;
0369     AlbumList referenceAlbums;
0370 
0371     for (auto* a: all)
0372     {
0373         const auto& path = static_cast<PAlbum*>(a)->albumPath();
0374 
0375         if (path.startsWith(QStringLiteral("/potentialDuplicates")))
0376         {
0377             // potentialDuplicates and subfolders
0378 
0379             referenceAlbums << a;
0380         }
0381     }
0382 
0383     QHash<ImagePath, QList<ItemInfo>> references;
0384     START_SEARCHING_DUPLICATES;
0385 
0386     QCOMPARE(references.count(), 3);
0387 
0388     // Undefined which one is used, because both have the same time, but at least one of the is available
0389 
0390     QVERIFY(references.contains(QLatin1String("Collection/2020/LargerSmaller.png")) !=
0391             references.contains(QLatin1String("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png")));
0392 
0393     // Both have same creation date
0394 
0395     QVERIFY(references.contains(QStringLiteral("Collection/2021/2.png")) !=
0396             references.contains(QStringLiteral("Collection/potentialDuplicates/subfolder/2.png")));
0397 
0398     // Undefined which one is used, because both have the same time, but at least one of the is available
0399 
0400     QVERIFY(references.contains(QStringLiteral("Collection/2023/4.png")) !=
0401             references.contains(QStringLiteral("Collection/potentialDuplicates/4.png")));
0402 }
0403 
0404 void HaarIfaceTest::testPreferNewerModificationDate()
0405 {
0406     const auto refImageSelMethod = HaarIface::RefImageSelMethod::NewerModificationDate;
0407     AlbumList all                = AlbumManager::instance()->allPAlbums();
0408 
0409     AlbumList tags; // empty
0410     AlbumList searchAlbums = all;
0411     AlbumList referenceAlbums;
0412 
0413     for (auto* a: all)
0414     {
0415         const auto& path = static_cast<PAlbum*>(a)->albumPath();
0416 
0417         if (path.startsWith(QStringLiteral("/potentialDuplicates")))
0418         {
0419             // potentialDuplicates and subfolders
0420 
0421             referenceAlbums << a;
0422         }
0423     }
0424 
0425     QHash<ImagePath, QList<ItemInfo>> references;
0426     START_SEARCHING_DUPLICATES;
0427 
0428     QCOMPARE(references.count(), 3);
0429 
0430     // Undefined which one is used, because both have the same time, but at least one of the is available
0431 
0432     QVERIFY(references.contains(QStringLiteral("Collection/2020/LargerSmaller.png")) !=
0433             references.contains(QStringLiteral("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png")));
0434 
0435     {
0436         QVERIFY(references.contains(QStringLiteral("Collection/2021/2.png"))); // This one is Newer
0437         auto duplicates = references.value(QStringLiteral("Collection/2021/2.png"));
0438         QCOMPARE(duplicates.count(), 1);
0439         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0440                  QStringLiteral("Collection/potentialDuplicates/subfolder/2.png"));
0441     }
0442 
0443     // Undefined which one is used, because both have the same time, but at least one of the is available
0444 
0445     QVERIFY(references.contains(QStringLiteral("Collection/2023/4.png")) !=
0446             references.contains(QStringLiteral("Collection/potentialDuplicates/4.png")));
0447 }
0448 
0449 void HaarIfaceTest::testPreferFolderWhole()
0450 {
0451     const auto refImageSelMethod = HaarIface::RefImageSelMethod::PreferFolder;
0452 
0453     AlbumList all = AlbumManager::instance()->allPAlbums();
0454 
0455     AlbumList tags; // empty
0456     AlbumList searchAlbums    = all;
0457     AlbumList referenceAlbums = all;
0458 
0459     QHash<ImagePath, QList<ItemInfo>> references;
0460     START_SEARCHING_DUPLICATES;
0461 
0462     QCOMPARE(references.count(), 3);
0463 
0464     // Not relevant which one is used, but at least one of the is available
0465 
0466     QVERIFY(references.contains(QLatin1String("Collection/2020/LargerSmaller.png")) !=
0467             references.contains(QLatin1String("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png")));
0468 
0469     QVERIFY(references.contains(QStringLiteral("Collection/2023/4.png")) !=
0470             references.contains(QStringLiteral("Collection/potentialDuplicates/4.png")));
0471 
0472     QVERIFY(references.contains(QStringLiteral("Collection/2021/2.png")) !=
0473             references.contains(QStringLiteral("Collection/potentialDuplicates/subfolder/2.png")));
0474 }
0475 
0476 /*!
0477  * \brief HaarIfaceTest::testReferenceFolderNotSelected
0478  * The reference folder is not in the search folders.
0479  * But neverthless the folder shall be checked, otherwise
0480  * the duplicates get not found. The Duplicatesfinder will merge interally the
0481  * two album lists
0482  * The oposite that the folder is in both lists will be tested above, so
0483  * no extra test is needed.
0484  */
0485 void HaarIfaceTest::testReferenceFolderNotSelected()
0486 {
0487     const auto refImageSelMethod = HaarIface::RefImageSelMethod::ExcludeFolder;
0488 
0489     AlbumList all = AlbumManager::instance()->allPAlbums();
0490 
0491     AlbumList tags; // empty
0492     AlbumList searchAlbums;
0493 
0494     for (auto* a: all)
0495     {
0496         const auto& path = static_cast<PAlbum*>(a)->albumPath();
0497 
0498         if (!path.startsWith(QStringLiteral("/potentialDuplicates")))
0499         {
0500             // exclude potential duplicates
0501             // Collection/2020
0502             // Collection/2021
0503             // Collection/2022
0504             // Collection/2023
0505 
0506             searchAlbums << a;
0507         }
0508     }
0509 
0510     AlbumList referenceAlbums;
0511 
0512     for (auto* a: all)
0513     {
0514         const auto& path = static_cast<PAlbum*>(a)->albumPath();
0515 
0516         if (path.startsWith(QStringLiteral("/potentialDuplicates")))
0517         {
0518             // potentialDuplicates
0519 
0520             referenceAlbums << a;
0521         }
0522     }
0523 
0524     QHash<ImagePath, QList<ItemInfo>> references;
0525     START_SEARCHING_DUPLICATES;
0526 
0527     QCOMPARE(references.count(), 3);
0528 
0529     {
0530         QVERIFY(references.contains(QStringLiteral("Collection/2020/LargerSmaller.png")));
0531         auto duplicates = references.value(QStringLiteral("Collection/2020/LargerSmaller.png"));
0532         QCOMPARE(duplicates.count(), 1);
0533         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0534                  QStringLiteral("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png"));
0535     }
0536 
0537     {
0538         QVERIFY(references.contains(QStringLiteral("Collection/2021/2.png")));
0539         auto duplicates = references.value(QStringLiteral("Collection/2021/2.png"));
0540         QCOMPARE(duplicates.count(), 1);
0541         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0542                  QStringLiteral("Collection/potentialDuplicates/subfolder/2.png"));
0543     }
0544 
0545     {
0546         QVERIFY(references.contains(QStringLiteral("Collection/2023/4.png")));
0547         auto duplicates = references.value(QStringLiteral("Collection/2023/4.png"));
0548         QCOMPARE(duplicates.count(), 1);
0549         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0550                  QStringLiteral("Collection/potentialDuplicates/4.png"));
0551     }
0552 }
0553 
0554 /*!
0555  * \brief HaarIfaceTest::testReferenceFolderNotSelected
0556  * Similar test to testReferenceFolderNotSelected(), but with the difference,
0557  * "Collection/potentialDuplicates/subfolder" is in both, the reference and in the search albums
0558  */
0559 void HaarIfaceTest::testReferenceFolderPartlySelected()
0560 {
0561     const auto refImageSelMethod = HaarIface::RefImageSelMethod::ExcludeFolder;
0562 
0563     AlbumList all = AlbumManager::instance()->allPAlbums();
0564 
0565     AlbumList tags; // empty
0566     AlbumList searchAlbums;
0567 
0568     for (auto* a: all)
0569     {
0570         const auto& path = static_cast<PAlbum*>(a)->albumPath();
0571 
0572         if (
0573             !path.startsWith(QStringLiteral("/potentialDuplicates")) ||
0574             (
0575              path.startsWith(QStringLiteral("/potentialDuplicates/subfolder")) &&
0576              !path.contains(QStringLiteral("subsubfolder"))
0577             )
0578            )
0579         {
0580             // exclude potential duplicates but not the subfolder
0581             // Collection/2020
0582             // Collection/2021
0583             // Collection/2022
0584             // Collection/2023
0585             // Collection/potentialDuplicates/subfolder
0586             searchAlbums << a;
0587         }
0588     }
0589 
0590     AlbumList referenceAlbums;
0591 
0592     for (auto* a: all)
0593     {
0594         const auto& path = static_cast<PAlbum*>(a)->albumPath();
0595 
0596         if (path.startsWith(QStringLiteral("/potentialDuplicates")))
0597         {
0598             // potentialDuplicates
0599 
0600             referenceAlbums << a;
0601         }
0602     }
0603 
0604     QHash<ImagePath, QList<ItemInfo>> references;
0605     START_SEARCHING_DUPLICATES;
0606 
0607     QCOMPARE(references.count(), 3);
0608 
0609     {
0610         QVERIFY(references.contains(QStringLiteral("Collection/2020/LargerSmaller.png")));
0611         auto duplicates = references.value(QStringLiteral("Collection/2020/LargerSmaller.png"));
0612         QCOMPARE(duplicates.count(), 1);
0613         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0614                  QStringLiteral("Collection/potentialDuplicates/subfolder/subsubfolder/LargerSmaller.png"));
0615     }
0616 
0617     {
0618         QVERIFY(references.contains(QStringLiteral("Collection/2021/2.png")));
0619         auto duplicates = references.value(QStringLiteral("Collection/2021/2.png"));
0620         QCOMPARE(duplicates.count(), 1);
0621         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0622                  QStringLiteral("Collection/potentialDuplicates/subfolder/2.png"));
0623     }
0624 
0625     {
0626         QVERIFY(references.contains(QStringLiteral("Collection/2023/4.png")));
0627         auto duplicates = references.value(QStringLiteral("Collection/2023/4.png"));
0628         QCOMPARE(duplicates.count(), 1);
0629         QCOMPARE(PATHFROMFILEINFO(duplicates.at(0)),
0630                  QStringLiteral("Collection/potentialDuplicates/4.png"));
0631     }
0632 }
0633 
0634 HaarIfaceTest::~HaarIfaceTest()
0635 {
0636 }
0637 
0638 QTEST_MAIN(HaarIfaceTest)
0639 
0640 #include "moc_haariface_utest.cpp"