Browse Source

Exercise avatar crop gestures, gallery navigation and EXIF originals

master
evgeny 5 days ago
parent
commit
96af98f063
  1. 3
      tools/chatgui/CMakeLists.txt
  2. 54
      tools/chatgui/tests/test_avatars.cpp

3
tools/chatgui/CMakeLists.txt

@ -286,7 +286,8 @@ target_link_libraries(test_member_files_browser PRIVATE ${QT_LIBS} ${QT_TEST_LIB
add_test(NAME test_member_files_browser COMMAND test_member_files_browser)
set_tests_properties(test_member_files_browser PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
add_executable(test_avatars tests/test_avatars.cpp src/avatars/avatarcache.cpp src/avatars/avatarmanager.cpp db/db_manager.cpp)
add_executable(test_avatars tests/test_avatars.cpp src/avatars/avatarcache.cpp src/avatars/avatarmanager.cpp
src/avatars/avatarcrop.cpp src/avatars/avatargallery.cpp src/imageviewer_window.cpp db/db_manager.cpp)
target_link_libraries(test_avatars PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun pthread)
add_test(NAME test_avatars COMMAND test_avatars)
set_tests_properties(test_avatars PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 60)

54
tools/chatgui/tests/test_avatars.cpp

@ -1,5 +1,8 @@
/* Настоящие core/storage, Qt worker и кеш: два канала, публикация после COMMIT и restart. */
#include "../src/avatars/avatarmanager.h"
#include "../src/avatars/avatarcrop.h"
#include "../src/avatars/avatargallery.h"
#include "../src/imageviewer_window.h"
#include "../db/db_manager.h"
#include "../transport/gui_bridge.h"
#include <QtTest>
@ -7,6 +10,8 @@
#include <QFile>
#include <QCryptographicHash>
#include <QPainter>
#include <QDialog>
#include <QPushButton>
extern "C" {
#include "utun_instance.h"
#include "chat/chat_core.h"
@ -99,6 +104,44 @@ private slots:
QVERIFY(!AvatarCache::prepare(input,directory.path(),QRectF(0.7,0,0.5,1)).error.isEmpty());
}
void exifRotationKeepsOriginalBytesAndSelectedArea() {
QTemporaryDir directory; QVERIFY(directory.isValid());
QImage image(800,400,QImage::Format_RGB32); image.fill(Qt::blue);
QPainter painter(&image); painter.fillRect(QRect(0,0,400,400),Qt::red); painter.end();
QByteArray jpeg; QBuffer buffer(&jpeg); QVERIFY(buffer.open(QIODevice::WriteOnly)); QVERIFY(image.save(&buffer,"JPEG",95));
const QByteArray exif=QByteArray::fromHex("ffe1002245786966000049492a0008000000010012010300010000000600000000000000");
const QByteArray original=jpeg.left(2)+exif+jpeg.mid(2);
const QString path=directory.path()+"/rotated.jpg"; QFile file(path); QVERIFY(file.open(QIODevice::WriteOnly));
QCOMPARE(file.write(original),qint64(original.size())); file.close();
const auto prepared=AvatarCache::prepare(path,directory.path(),QRectF(0,0,1,0.5));
QVERIFY2(prepared.error.isEmpty(),qPrintable(prepared.error)); QCOMPARE(prepared.record.size,QSize(400,800));
const auto loaded=AvatarCache::load(directory.path()+'/'+prepared.hash+".json",prepared.hash);
QVERIFY(loaded.image.pixelColor(128,128).red()>240);
QFile stored(directory.path()+'/'+prepared.record.original); QVERIFY(stored.open(QIODevice::ReadOnly)); QCOMPARE(stored.readAll(),original);
}
void editorDragSelectsTheEdgeAndCancelDoesNotPrepareFiles() {
QTemporaryDir directory; QVERIFY(directory.isValid());
QImage image(800,400,QImage::Format_RGB32); image.fill(Qt::blue);
const QString source=directory.path()+"/source.png"; QVERIFY(image.save(source));
QTimer automate; automate.setInterval(10);
connect(&automate,&QTimer::timeout,this,[] {
auto* dialog=QApplication::activeModalWidget(); if (!dialog) return;
auto* view=dialog->findChild<QWidget*>("avatarCropView"); auto* upload=dialog->findChild<QPushButton*>("avatarCropUpload");
if (!view || !upload || !upload->isEnabled()) return;
const QPoint center=view->rect().center();
QTest::mousePress(view,Qt::LeftButton,Qt::NoModifier,center);
QTest::mouseMove(view,center+QPoint(1000,0)); QTest::mouseRelease(view,Qt::LeftButton,Qt::NoModifier,center+QPoint(1000,0));
QTest::mouseClick(upload,Qt::LeftButton);
});
automate.start(); QRectF crop; QVERIFY(selectAvatarCrop(source,crop,nullptr)); automate.stop();
QVERIFY(qAbs(crop.x())<0.001); QVERIFY(qAbs(crop.y())<0.001);
QVERIFY(qAbs(crop.width()-0.5)<0.001); QVERIFY(qAbs(crop.height()-1)<0.001);
QTimer::singleShot(10,[] { if (auto* dialog=qobject_cast<QDialog*>(QApplication::activeModalWidget())) dialog->reject(); });
QVERIFY(!selectAvatarCrop(source,crop,nullptr));
QCOMPARE(QDir(directory.path()).entryList({"*.json","*.webp"},QDir::Files).size(),0);
}
void uploadReplicateCacheRestartAndRemove() {
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
debug_set_category_level(DEBUG_CATEGORY_CHAT_SYNC, DEBUG_LEVEL_DEBUG);
@ -208,6 +251,17 @@ private slots:
QCOMPARE(manager.galleryImage(selected,true).size(),QSize(300,200));
QVERIFY(manager.galleryImage(selected,true).pixelColor(0,0).red()>240);
manager.closeGallery();
showAvatarGallery(channels[0].channelId,testInstance->node_id);
QDialog* gallery=nullptr;
for (auto* widget : QApplication::topLevelWidgets()) if (widget->windowTitle()=="Avatars") gallery=qobject_cast<QDialog*>(widget);
QVERIFY(gallery); auto* viewer=gallery->findChild<ImageViewerWindow*>(); QVERIFY(viewer);
QTRY_VERIFY_WITH_TIMEOUT(viewer->grab().toImage().pixelColor(viewer->rect().center()).red()>240,5000);
for (int i=0;i<5;i++) QVERIFY(gallery->findChild<QPushButton*>(QString("avatarPreview%1").arg(i)));
QTRY_COMPARE_WITH_TIMEOUT(manager.gallery().size(),2,5000);
auto* next=gallery->findChild<QPushButton*>(manager.gallery().indexOf(selected)==0 ? "avatarNext" : "avatarPrevious");
QVERIFY(next); QTest::mouseClick(next,Qt::LeftButton);
QTRY_VERIFY_WITH_TIMEOUT(viewer->grab().toImage().pixelColor(viewer->rect().center()).blue()>240,5000);
gallery->close(); QTRY_VERIFY_WITH_TIMEOUT(manager.gallery().isEmpty(),5000);
manager.clearDefault();
for (const auto& channel : channels) {
uint8_t wire[CHAT_MEMBER_DISPLAY_SIZE];

Loading…
Cancel
Save