Browse Source

Test avatar originals, selected lossy crops and storage limits

master
evgeny 7 days ago
parent
commit
ab22277e7b
  1. 6
      tests/test_member_files.c
  2. 41
      tools/chatgui/tests/test_avatars.cpp

6
tests/test_member_files.c

@ -59,7 +59,11 @@ static void avatar_storage_test(const char* directory) {
memset(q.upload, 2, 16); run(s, 55, 77, MF_BEGIN_WRITE, MF_EXISTS);
memcpy(q.version, version, 16); run(s, 55, 77, MF_BEGIN_WRITE, MF_EXISTS);
memset(q.version, 0, 16); q.hash[0] ^= 1; run(s, 55, 77, MF_BEGIN_WRITE, MF_HASH_MISMATCH); q.hash[0] ^= 1;
q.size = MF_AVATAR_MAX_BYTES + 1; run(s, 55, 77, MF_BEGIN_WRITE, MF_INVALID_RANGE);
q.size = MF_AVATAR_ORIGINAL_MAX_BYTES + 1; run(s, 55, 77, MF_BEGIN_WRITE, MF_INVALID_RANGE);
snprintf(q.path, sizeof(q.path), "avatars/%s.json", hash);
q.size = MF_AVATAR_MANIFEST_MAX_BYTES + 1; run(s, 55, 77, MF_BEGIN_WRITE, MF_INVALID_RANGE);
EXPECT(mf_avatar_manifest_valid(q.path + 8), "manifest name accepted");
snprintf(q.path, sizeof(q.path), "avatars/%s.png", hash);
q.size = 0; run(s, 55, 77, MF_BEGIN_WRITE, MF_INVALID_RANGE);
memcpy(q.version, version, 16); snprintf(q.target, sizeof(q.target), "renamed.png"); run(s, 55, 77, MF_RENAME, MF_INVALID_PATH);
snprintf(q.path, sizeof(q.path), "Avatars/%s.png", hash); run(s, 55, 77, MF_BEGIN_WRITE, MF_INVALID_PATH);

41
tools/chatgui/tests/test_avatars.cpp

@ -65,7 +65,11 @@ private slots:
const QString input = directory.path() + "/input.jpg"; QVERIFY(source.save(input));
const auto prepared = AvatarCache::prepare(input, directory.path());
QVERIFY2(!prepared.image.isNull(), qPrintable(prepared.error)); QCOMPARE(prepared.image.size(), QSize(256, 256));
const QString path = directory.path() + '/' + prepared.hash + ".png";
const QString path = directory.path() + '/' + prepared.hash + ".json";
QFile original(input), stored(directory.path() + '/' + prepared.record.original);
QVERIFY(original.open(QIODevice::ReadOnly)); QVERIFY(stored.open(QIODevice::ReadOnly)); QCOMPARE(stored.readAll(),original.readAll());
QFile webp(directory.path() + '/' + prepared.record.preview); QVERIFY(webp.open(QIODevice::ReadOnly));
const QByteArray encoded=webp.readAll(); QCOMPARE(encoded.left(4),QByteArray("RIFF")); QVERIFY(encoded.contains("VP8 "));
QVERIFY(!AvatarCache::load(path, prepared.hash).image.isNull());
QVERIFY(AvatarCache::load(path, QString(64, '0')).image.isNull());
QFile corrupt(path); QVERIFY(corrupt.open(QIODevice::Append)); QCOMPARE(corrupt.write("x"), 1LL); corrupt.close();
@ -75,11 +79,25 @@ private slots:
const QString hash = QCryptographicHash::hash(bytes, QCryptographicHash::Sha256).toHex();
const QString bad = directory.path() + "/bad.download"; QFile output(bad); QVERIFY(output.open(QIODevice::WriteOnly));
QCOMPARE(output.write(bytes), qint64(bytes.size())); output.close();
QVERIFY(AvatarCache::publish(bad, directory.path(), hash).image.isNull()); QVERIFY(!QFile::exists(bad));
QVERIFY(!AvatarCache::publish(bad, directory.path(), hash + ".webp").error.isEmpty()); QVERIFY(!QFile::exists(bad));
QFile partial(directory.path() + "/x.png.utun-123.part"); QVERIFY(partial.open(QIODevice::WriteOnly)); partial.close();
QVERIFY(AvatarCache::initialize(directory.path())); QVERIFY(!partial.exists());
}
void selectedSquarePreservesOriginal() {
QTemporaryDir directory; QVERIFY(directory.isValid());
QImage source(800,400,QImage::Format_RGB32); source.fill(Qt::blue);
QPainter painter(&source); painter.fillRect(QRect(0,0,400,400),Qt::red); painter.end();
const QString input=directory.path()+"/source.png"; QVERIFY(source.save(input));
const auto prepared=AvatarCache::prepare(input,directory.path(),QRectF(0,0,0.5,1));
QVERIFY2(prepared.error.isEmpty(),qPrintable(prepared.error)); QCOMPARE(prepared.record.crop,QRectF(0,0,0.5,1));
const auto loaded=AvatarCache::load(directory.path()+'/'+prepared.hash+".json",prepared.hash);
QVERIFY2(loaded.error.isEmpty(),qPrintable(loaded.error)); QVERIFY(loaded.image.pixelColor(128,128).red()>240);
const auto full=AvatarCache::readObject(directory.path()+'/'+prepared.record.original,prepared.record.original);
QCOMPARE(full.image,source);
QVERIFY(!AvatarCache::prepare(input,directory.path(),QRectF(0.7,0,0.5,1)).error.isEmpty());
}
void uploadReplicateCacheRestartAndRemove() {
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
debug_set_category_level(DEBUG_CATEGORY_CHAT_SYNC, DEBUG_LEVEL_DEBUG);
@ -125,6 +143,12 @@ private slots:
QVERIFY(mf_avatar_file_valid(member.avatar_file));
QVERIFY(QFile::exists(directory.path() + "/storage/" + channel.channelId + '/' + QString::number(testInstance->node_id) +
"/avatars/" + member.avatar_file));
const QString root=directory.path()+"/storage/"+channel.channelId+'/'+QString::number(testInstance->node_id)+"/avatars/";
const auto bundle=AvatarCache::readObject(root+member.avatar_file,member.avatar_file);
QVERIFY2(bundle.error.isEmpty(),qPrintable(bundle.error));
QFile original(source), uploaded(root+bundle.record.original);
QVERIFY(original.open(QIODevice::ReadOnly)); QVERIFY(uploaded.open(QIODevice::ReadOnly)); QCOMPARE(uploaded.readAll(),original.readAll());
QVERIFY(QFile::exists(root+bundle.record.preview));
QVERIFY(!manager.image(channel.channelId, testInstance->node_id).isNull());
QVERIFY(!manager.image("pm:test", testInstance->node_id).isNull());
cached = directory.path() + "/avatar_cache/" + QString::number(testInstance->node_id, 16) + '/' + member.avatar_file;
@ -149,7 +173,7 @@ private slots:
QCOMPARE(sc_ed25519_verify(testInstance->my_ed25519_pubkey, signedBytes, length, signature), SC_OK);
uint8_t wire[CHAT_MEMBER_DISPLAY_SIZE]; QCOMPARE(chat_core_get_single_member(testInstance, channel.channelId.toLatin1().constData(), testInstance->node_id, wire), 0);
QCOMPARE(mf_get64(wire + 79), testInstance->node_id);
QCOMPARE(manager.image(channel.channelId, testInstance->node_id).pixelColor(128, 128), QColor(Qt::blue));
QVERIFY(manager.image(channel.channelId, testInstance->node_id).pixelColor(128,128).blue()>240);
}
uasync_poll(ua, 0);
}
@ -169,13 +193,20 @@ private slots:
manager.uploadDefault(replacement, testInstance->node_id);
auto isRed = [&manager, &db](const QString& channel) {
const QImage current = manager.image(channel, db.myNodeId());
return !current.isNull() && current.pixelColor(128, 128) == QColor(Qt::red);
return !current.isNull() && current.pixelColor(128,128).red()>240;
};
for (const auto& channel : channels)
QTRY_VERIFY_WITH_TIMEOUT(isRed(channel.channelId), 10000);
deferDownload = false; manager.onTransfer((const uint8_t*)delayedDownload.constData(), delayedDownload.size());
QTRY_VERIFY_WITH_TIMEOUT(QFile::exists(cached), 5000);
for (const auto& channel : channels) QCOMPARE(manager.image(channel.channelId, testInstance->node_id).pixelColor(128, 128), QColor(Qt::red));
for (const auto& channel : channels) QVERIFY(manager.image(channel.channelId,testInstance->node_id).pixelColor(128,128).red()>240);
manager.openGallery(channels[0].channelId,testInstance->node_id);
QTRY_COMPARE_WITH_TIMEOUT(manager.gallery().size(),2,5000);
const QString selected=manager.galleryCurrent();
QTRY_VERIFY_WITH_TIMEOUT(!manager.galleryImage(selected,true).isNull(),10000);
QCOMPARE(manager.galleryImage(selected,true).size(),QSize(300,200));
QVERIFY(manager.galleryImage(selected,true).pixelColor(0,0).red()>240);
manager.closeGallery();
manager.clearDefault();
for (const auto& channel : channels) {
uint8_t wire[CHAT_MEMBER_DISPLAY_SIZE];

Loading…
Cancel
Save