1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2021-02-20
7  * Description : Unit tests for TagsCache class
8  *
9  * Copyright (C) 2021 by David Haslam, <dch dot code at gmail dot com>
10  *
11  * This program is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation;
14  * either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 #include "tagscache_utest.h"
25 
26 // C++ includes
27 
28 #include <set>
29 
30 // Qt includes
31 
32 #include <QString>
33 #include <QDebug>
34 
35 // Local includes
36 
37 #include "coredb.h"
38 #include "coredbaccess.h"
39 
TagsCacheTest(QObject * const parent)40 TagsCacheTest::TagsCacheTest(QObject* const parent)
41     : QObject  (parent),
42       tagsCache(nullptr)
43 {
44 }
45 
~TagsCacheTest()46 TagsCacheTest::~TagsCacheTest()
47 {
48 }
49 
initTestCase()50 void TagsCacheTest::initTestCase()
51 {
52     qDebug() << "initTestCase()";
53 
54     Digikam::DbEngineParameters db_params
55     (
56         QString::fromUtf8("QSQLITE"),      // databaseType
57         QString::fromUtf8(":memory:"),     // databaseNameCore
58         QString::fromUtf8("")              // connectOptions
59     );
60 
61     Digikam::CoreDbAccess::setParameters(db_params);
62     QVERIFY(Digikam::CoreDbAccess::checkReadyForUse());
63     tagsCache = Digikam::TagsCache::instance();
64 }
65 
cleanupTestCase()66 void TagsCacheTest::cleanupTestCase()
67 {
68     qDebug() << "cleanupTestCase()";
69 }
70 
init()71 void TagsCacheTest::init()
72 {
73     QCOMPARE(countTags(), 0);
74 }
75 
cleanup()76 void TagsCacheTest::cleanup()
77 {
78     auto coredb = Digikam::CoreDbAccess().db();
79     auto tags   = coredb->getTagShortInfos();
80 
81     for (auto tag : tags)
82     {
83         coredb->deleteTag(tag.id);
84     }
85 
86     QCOMPARE(countTags(), 0);
87 }
88 
testSimpleHierarchy()89 void TagsCacheTest::testSimpleHierarchy()
90 {
91     auto id       = tagsCache->createTag(QLatin1String("Top/Middle/Bottom"));
92 
93     dumpTags();
94     QCOMPARE(countTags(), 3);
95 
96     auto bottomId = tagsCache->tagForPath(QLatin1String("Top/Middle/Bottom"));
97     auto middleId = tagsCache->parentTag(id);
98     auto topId    = tagsCache->parentTag(middleId);
99 
100     QCOMPARE(id, bottomId);
101     QVERIFY(bottomId);
102     QVERIFY(middleId);
103     QVERIFY(topId);
104     QVERIFY(tagsCache->hasTag(bottomId));
105     QVERIFY(tagsCache->hasTag(middleId));
106     QVERIFY(tagsCache->hasTag(topId));
107     QCOMPARE(tagsCache->tagName(id),       QLatin1String("Bottom"));
108     QCOMPARE(tagsCache->tagName(middleId), QLatin1String("Middle"));
109     QCOMPARE(tagsCache->tagName(topId),    QLatin1String("Top"));
110 
111     auto bottomIds = tagsCache->tagsForName(QLatin1String("Bottom"));
112 
113     QCOMPARE(bottomIds.size(), 1);
114     QCOMPARE(bottomIds[0], bottomId);
115 }
116 
testComplexHierarchy()117 void TagsCacheTest::testComplexHierarchy()
118 {
119     tagsCache->createTag(QLatin1String("Top/Middle"));
120     tagsCache->createTag(QLatin1String("Top/Middle/First"));
121     tagsCache->createTag(QLatin1String("Top/Middle/Second"));
122     tagsCache->createTag(QLatin1String("Super/Top"));
123     tagsCache->createTag(QLatin1String("Super/Top/First"));
124     tagsCache->createTag(QLatin1String("Super/Top/Second"));
125     tagsCache->createTag(QLatin1String("Super/Top/Third"));
126     tagsCache->createTag(QLatin1String("Mixed Up/Third/Second"));
127     tagsCache->createTag(QLatin1String("Mixed Up/Third/First"));
128 
129     QCOMPARE(countTags(), 13);
130 
131     auto top_ids   = tagsCache->tagsForName(QLatin1String("Top"));
132     QCOMPARE(top_ids.size(), 2);
133 
134     auto first_ids = tagsCache->tagsForName(QLatin1String("First"));
135     QCOMPARE(first_ids.size(), 3);
136 }
137 
testRepeatedNames()138 void TagsCacheTest::testRepeatedNames()
139 {
140     tagsCache->createTag(QLatin1String("Repeat Me/Repeat Me/Repeat Me/Repeat Me"));
141 
142     auto repeatMeIds = tagsCache->tagsForName(QLatin1String("Repeat Me"));
143     QCOMPARE(repeatMeIds.size(), 4);
144 
145     // all ids should be unique
146 
147     std::set<int> set;
148 
149     for (auto id : repeatMeIds)
150     {
151         auto result = set.insert(id);
152         QVERIFY(result.second);
153     }
154 }
155 
testDuplicateTop()156 void TagsCacheTest::testDuplicateTop()
157 {
158     tagsCache->createTag(QLatin1String("Top/Middle/Bottom"));
159     tagsCache->createTag(QLatin1String("Super/Top/Middle/Bottom"));
160     tagsCache->createTag(QLatin1String("First/Super/Top"));
161     dumpTags();
162     QCOMPARE(countTags(), 10);
163 
164     // the single word 'Top' should match the top tag
165 
166     auto id1 = tagsCache->tagForPath(QLatin1String("Top"));
167     QVERIFY(id1);
168     QCOMPARE(tagsCache->tagPath(id1), QLatin1String("/Top"));
169 
170     // and it doesn't matter if there's a leading slash
171 
172     auto id2 = tagsCache->tagForPath(QLatin1String("/Top"));
173     QVERIFY(id2);
174     QCOMPARE(id1, id2);
175     QCOMPARE(tagsCache->tagPath(id2), QLatin1String("/Top"));
176 
177     // a more complex request
178 
179     auto id3 = tagsCache->tagForPath(QLatin1String("Super/Top"));
180     QVERIFY(id3);
181     QCOMPARE(tagsCache->tagPath(id3), QLatin1String("/Super/Top"));
182 }
183 
184 // utilities
185 
countTags()186 int TagsCacheTest::countTags()
187 {
188     auto coredb = Digikam::CoreDbAccess().db();
189     auto tags   = coredb->getTagShortInfos();
190 
191     return tags.size();
192 }
193 
194 // debug
195 
dumpTables()196 void TagsCacheTest::dumpTables()
197 {
198     auto sqlnames = QSqlDatabase::connectionNames();
199     auto sqldb    = QSqlDatabase::database(sqlnames[0]);
200     qDebug() << sqldb.tables();
201 }
202 
dumpTags()203 void TagsCacheTest::dumpTags()
204 {
205     auto coredb = Digikam::CoreDbAccess().db();
206     auto tags   = coredb->getTagShortInfos();
207 
208     for (auto it = tags.begin() ; it != tags.end() ; ++it)
209     {
210         qDebug() << it->id << it->pid << it->name;
211     }
212 }
213 
214 QTEST_GUILESS_MAIN(TagsCacheTest)
215