File indexing completed on 2024-05-12 15:55:37
0001 // SPDX-FileCopyrightText: 2021-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at> 0002 // 0003 // SPDX-License-Identifier: LicenseRef-KDE-Accepted-GPL 0004 0005 #include "TestThumbnailCache.h" 0006 0007 #include "ThumbnailCache.h" 0008 0009 #include <kpabase/SettingsData.h> 0010 #include <kpabase/UIDelegate.h> 0011 0012 #include <QBuffer> 0013 #include <QLoggingCategory> 0014 #include <QRegularExpression> 0015 #include <QSignalSpy> 0016 0017 namespace 0018 { 0019 constexpr auto msgPreconditionFailed = "Precondition for test failed - please fix unit test!"; 0020 constexpr auto v4IndexHexData { 0021 "00000004" // version 0022 "00000003" // current file 0023 "00033714" // offset in file 0024 "00000003" // number of thumbnails 0025 "000000160062006C00610063006B00690065002E006A00700067000000000000462C00001F0B" // "blackie.jpg" 0026 "0000001600730070006900660066005F0032002E006A0070006700000000000038A900001DFD" // "spiff_2.jpg" 0027 "0000001C006E00650077005F0077006100760065005F0032002E006A0070006700000000000000000000229D" // "new_wave_2.jpg" 0028 }; 0029 constexpr auto v5IndexHexData { 0030 "00000005" // version 0031 "00000100" // v5: thumbnailsize 0032 "00000003" // current file 0033 "00033714" // offset in file 0034 "00000003" // number of thumbnails 0035 "000000160062006C00610063006B00690065002E006A00700067000000000000462C00001F0B" // "blackie.jpg" 0036 "0000001600730070006900660066005F0032002E006A0070006700000000000038A900001DFD" // "spiff_2.jpg" 0037 "0000001C006E00650077005F0077006100760065005F0032002E006A0070006700000000000000000000229D" // "new_wave_2.jpg" 0038 }; 0039 } 0040 0041 void KPATest::TestThumbnailCache::initTestCase() 0042 { 0043 // ThumbnailCache uses QHash, which is randomized by default 0044 qSetGlobalQHashSeed(0); 0045 } 0046 0047 void KPATest::TestThumbnailCache::loadV4ThumbnailIndex() 0048 { 0049 QTemporaryDir tmpDir; 0050 QVERIFY2(tmpDir.isValid(), msgPreconditionFailed); 0051 // tmpDir.setAutoRemove(false); 0052 0053 DB::DummyUIDelegate uiDelegate; 0054 Settings::SettingsData::setup(tmpDir.path(), uiDelegate); 0055 0056 const QDir thumbnailDir { tmpDir.filePath(ImageManager::defaultThumbnailDirectory()) }; 0057 QDir().mkdir(thumbnailDir.path()); 0058 QFile thumbnailIndex { thumbnailDir.filePath(QStringLiteral("thumbnailindex")) }; 0059 QVERIFY2(thumbnailIndex.open(QIODevice::WriteOnly), msgPreconditionFailed); 0060 thumbnailIndex.write(QByteArray::fromHex(v4IndexHexData)); 0061 thumbnailIndex.close(); 0062 QCOMPARE(thumbnailIndex.size(), 136); 0063 0064 ImageManager::ThumbnailCache thumbnailCache { thumbnailDir.path() }; 0065 0066 QSignalSpy cacheSavedSpy { &thumbnailCache, &ImageManager::ThumbnailCache::saveComplete }; 0067 QVERIFY2(cacheSavedSpy.isValid(), msgPreconditionFailed); 0068 0069 // change this when the version changes: 0070 QCOMPARE(thumbnailCache.preferredFileVersion(), 5); 0071 // verify input as defined in v4IndexHexData: 0072 QCOMPARE(thumbnailCache.actualFileVersion(), 4); 0073 QCOMPARE(thumbnailCache.size(), 3); 0074 QVERIFY(thumbnailCache.contains(DB::FileName::fromRelativePath(QStringLiteral("blackie.jpg")))); 0075 QVERIFY(thumbnailCache.contains(DB::FileName::fromRelativePath(QStringLiteral("spiff_2.jpg")))); 0076 QVERIFY(thumbnailCache.contains(DB::FileName::fromRelativePath(QStringLiteral("new_wave_2.jpg")))); 0077 QVERIFY(!thumbnailCache.contains(DB::FileName())); 0078 0079 // remove an empty file list to force the dirty flag: 0080 thumbnailCache.removeThumbnails(DB::FileNameList()); 0081 // actually, removeThumbnails causes a save, but in case we change we want to call save explicitly: 0082 thumbnailCache.save(); 0083 // save is actually called more than once, but should only be executed once: 0084 QCOMPARE(cacheSavedSpy.count(), 1); 0085 0086 // after saving, the actual file version should have been updated 0087 QCOMPARE(thumbnailCache.actualFileVersion(), thumbnailCache.preferredFileVersion()); 0088 QCOMPARE(thumbnailCache.thumbnailSize(), Settings::SettingsData::instance()->thumbnailSize()); 0089 0090 // verify data on disk: 0091 QVERIFY2(thumbnailIndex.open(QIODevice::ReadOnly), msgPreconditionFailed); 0092 const QByteArray v5Index { thumbnailIndex.readAll() }; 0093 thumbnailIndex.close(); 0094 QCOMPARE(v5Index, QByteArray::fromHex(v5IndexHexData)); 0095 0096 // we only have the index data - trying a lookup won't work, but shouldn't crash or something 0097 QTest::ignoreMessage(QtWarningMsg, "Failed to open thumbnail file"); 0098 QTest::ignoreMessage(QtWarningMsg, "Failed to map thumbnail file"); 0099 QTest::ignoreMessage(QtWarningMsg, "Failed to map thumbnail file"); 0100 QVERIFY(thumbnailCache.lookup(DB::FileName::fromRelativePath(QStringLiteral("blackie.jpg"))).isNull()); 0101 0102 QSignalSpy flushedSpy { &thumbnailCache, &ImageManager::ThumbnailCache::cacheFlushed }; 0103 QVERIFY2(flushedSpy.isValid(), msgPreconditionFailed); 0104 thumbnailCache.flush(); 0105 QCOMPARE(flushedSpy.count(), 1); 0106 QCOMPARE(thumbnailCache.size(), 0); 0107 } 0108 0109 void KPATest::TestThumbnailCache::insertRemove() 0110 { 0111 QTemporaryDir tmpDir; 0112 QVERIFY2(tmpDir.isValid(), msgPreconditionFailed); 0113 // tmpDir.setAutoRemove(false); 0114 0115 DB::DummyUIDelegate uiDelegate; 0116 Settings::SettingsData::setup(tmpDir.path(), uiDelegate); 0117 0118 const QDir thumbnailDir { tmpDir.filePath(ImageManager::defaultThumbnailDirectory()) }; 0119 QDir().mkdir(thumbnailDir.path()); 0120 0121 const QRegularExpression thumbnailIndexNotFoundRegex { QStringLiteral("Thumbnail index file \"%1\" not found!") 0122 .arg(thumbnailDir.filePath(QStringLiteral("thumbnailindex"))) }; 0123 QTest::ignoreMessage(QtWarningMsg, thumbnailIndexNotFoundRegex); 0124 ImageManager::ThumbnailCache thumbnailCache { thumbnailDir.path() }; 0125 0126 QSignalSpy cacheSavedSpy { &thumbnailCache, &ImageManager::ThumbnailCache::saveComplete }; 0127 QVERIFY2(cacheSavedSpy.isValid(), msgPreconditionFailed); 0128 0129 thumbnailCache.save(); 0130 QCOMPARE(thumbnailCache.size(), 0); 0131 // nothing stored yet - no need to save: 0132 QCOMPARE(cacheSavedSpy.count(), 0); 0133 QCOMPARE(thumbnailCache.actualFileVersion(), -1); 0134 0135 // insert some images 0136 QSignalSpy thumbnailUpdatedSpy { &thumbnailCache, &ImageManager::ThumbnailCache::thumbnailUpdated }; 0137 QVERIFY2(thumbnailUpdatedSpy.isValid(), msgPreconditionFailed); 0138 // the image needs to be valid 0139 QImage nullImage {}; 0140 const auto nullImageFileName = DB::FileName::fromRelativePath(QStringLiteral("nullImage.jpg")); 0141 QTest::ignoreMessage(QtWarningMsg, "Thumbnail for file \"nullImage.jpg\" is invalid!"); 0142 thumbnailCache.insert(nullImageFileName, nullImage); 0143 QCOMPARE(thumbnailCache.size(), 0); 0144 QVERIFY(!thumbnailCache.contains(nullImageFileName)); 0145 QCOMPARE(thumbnailUpdatedSpy.count(), 0); 0146 0147 const int thumbnailSize = thumbnailCache.thumbnailSize(); 0148 QVERIFY2(thumbnailSize > 0, "Thumbnail size must be greater than 0!"); 0149 QImage someImage { thumbnailSize + 1, thumbnailSize + 1, QImage::Format_RGB32 }; 0150 someImage.fill(Qt::red); 0151 QVERIFY(!someImage.isNull()); 0152 const auto someImageFileName = DB::FileName::fromRelativePath(QStringLiteral("someImage.jpg")); 0153 thumbnailCache.insert(someImageFileName, someImage); 0154 QCOMPARE(thumbnailCache.size(), 1); 0155 QVERIFY(thumbnailCache.contains(someImageFileName)); 0156 QCOMPARE(thumbnailUpdatedSpy.count(), 1); 0157 thumbnailUpdatedSpy.clear(); 0158 0159 QImage otherImage { thumbnailSize, thumbnailSize, QImage::Format_RGB32 }; 0160 otherImage.fill(Qt::green); 0161 QVERIFY(!otherImage.isNull()); 0162 const auto otherImageFileName = DB::FileName::fromRelativePath(QStringLiteral("otherImage.jpg")); 0163 thumbnailCache.insert(otherImageFileName, otherImage); 0164 QCOMPARE(thumbnailCache.size(), 2); 0165 QVERIFY(thumbnailCache.contains(otherImageFileName)); 0166 QCOMPARE(thumbnailUpdatedSpy.count(), 1); 0167 thumbnailUpdatedSpy.clear(); 0168 0169 // TODO(jzarl) inserted images should be the same as the ones we look up 0170 QByteArray someImageData; 0171 QBuffer someImageBuffer(&someImageData); 0172 bool OK = someImageBuffer.open(QIODevice::WriteOnly); 0173 QVERIFY2(OK, "someImageBuffer.open() failed!"); 0174 OK = someImage.save(&someImageBuffer, "JPG"); 0175 QVERIFY2(OK, "Writing someImage into buffer failed!"); 0176 0177 thumbnailCache.removeThumbnail(someImageFileName); 0178 QCOMPARE(thumbnailCache.size(), 1); 0179 QVERIFY(!thumbnailCache.contains(someImageFileName)); 0180 thumbnailCache.insert(someImageFileName, someImageData); 0181 QCOMPARE(thumbnailCache.size(), 2); 0182 QVERIFY(thumbnailCache.contains(someImageFileName)); 0183 const auto someImageCacheData = thumbnailCache.lookupRawData(someImageFileName); 0184 QCOMPARE(someImageCacheData, someImageData); 0185 0186 // this should do nothing: 0187 thumbnailCache.removeThumbnails(DB::FileNameList()); 0188 QCOMPARE(thumbnailCache.size(), 2); 0189 QCOMPARE(thumbnailCache.actualFileVersion(), thumbnailCache.preferredFileVersion()); 0190 0191 thumbnailCache.save(); 0192 // the someImage has an incorrect size: 0193 QCOMPARE(thumbnailCache.findIncorrectlySizedThumbnails().size(), 1); 0194 0195 // removals: 0196 QVERIFY(thumbnailCache.contains(someImageFileName)); 0197 QVERIFY(thumbnailCache.contains(otherImageFileName)); 0198 thumbnailCache.removeThumbnail(someImageFileName); 0199 QCOMPARE(thumbnailCache.size(), 1); 0200 QVERIFY(!thumbnailCache.contains(someImageFileName)); 0201 QVERIFY(thumbnailCache.contains(otherImageFileName)); 0202 thumbnailCache.save(); 0203 QVERIFY(thumbnailCache.findIncorrectlySizedThumbnails().isEmpty()); 0204 0205 thumbnailCache.removeThumbnails(DB::FileNameList({ otherImageFileName })); 0206 QCOMPARE(thumbnailCache.size(), 0); 0207 0208 // insert again and invalidate by changing thumbnail size: 0209 thumbnailCache.insert(someImageFileName, someImage); 0210 thumbnailCache.insert(otherImageFileName, otherImage); 0211 QCOMPARE(thumbnailCache.size(), 2); 0212 QSignalSpy invalidatedSpy { &thumbnailCache, &ImageManager::ThumbnailCache::cacheInvalidated }; 0213 QVERIFY(invalidatedSpy.isValid()); 0214 thumbnailCache.setThumbnailSize(thumbnailSize + 1); 0215 QCOMPARE(invalidatedSpy.count(), 1); 0216 QCOMPARE(thumbnailCache.size(), 0); 0217 } 0218 0219 QTEST_MAIN(KPATest::TestThumbnailCache) 0220 0221 // vi:expandtab:tabstop=4 shiftwidth=4: 0222 0223 #include "moc_TestThumbnailCache.cpp"