Browse Source

Verify delayed file MIME across success failure and cancellation

master
evgeny 2 days ago
parent
commit
6d8c28f228
  1. 2
      tools/chatgui/src/member_files/browser.cpp
  2. 56
      tools/chatgui/tests/test_member_files_browser.cpp

2
tools/chatgui/src/member_files/browser.cpp

@ -626,7 +626,7 @@ void MemberFileBrowser::exportFile(bool clipboard) {
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "file browser: drag data ready id=%llu local=%s", (unsigned long long)id, qPrintable(local));
return local;
};
auto* drag = new QDrag(m_entries); drag->setParent(QCoreApplication::instance()); drag->setMimeData(mime);
auto* drag = new QDrag(m_entries); drag->setMimeData(mime); drag->setParent(QCoreApplication::instance());
// MIME живёт до возврата из native drag, даже если окно файлов закрыли во вложенном цикле событий.
connect(this, &QObject::destroyed, drag, [] { QDrag::cancel(); });
Qt::DropAction action = drag->exec(Qt::CopyAction, Qt::CopyAction);

56
tools/chatgui/tests/test_member_files_browser.cpp

@ -24,6 +24,7 @@
#include <QDrag>
#include <QMouseEvent>
#include <QScopeGuard>
#include <QChildEvent>
#include <functional>
extern "C" {
#include "member_files/member_files.h"
@ -77,6 +78,20 @@ static QPushButton* cancelButton(MemberFileBrowser& browser) {
return nullptr;
}
// Offscreen не имеет native drag. Получатель запрашивает реальный MIME при публикации QDrag приложению.
class DragReceiver : public QObject {
public:
std::function<void(const QMimeData*)> receive;
protected:
bool eventFilter(QObject* object, QEvent* event) override {
if (object == QCoreApplication::instance() && event->type() == QEvent::ChildAdded) {
auto* drag = qobject_cast<QDrag*>(static_cast<QChildEvent*>(event)->child());
if (drag && drag->mimeData()) receive(drag->mimeData());
}
return false;
}
};
class BrowserTest : public QObject {
Q_OBJECT
private slots:
@ -87,7 +102,15 @@ private slots:
}
void init() { transfers.clear(); cancelled.clear(); ready = true; transferStarted = {}; }
void exportToSystemClipboardAndSingleDrag_data() {
QTest::addColumn<int>("dragStatus");
QTest::newRow("success") << int(MF_OK);
QTest::newRow("failure") << int(MF_IO_ERROR);
QTest::newRow("cancel") << int(MF_CANCELLED);
}
void exportToSystemClipboardAndSingleDrag() {
QFETCH(int, dragStatus);
QTemporaryDir cache; QVERIFY(cache.isValid()); QByteArray oldCache = qgetenv("XDG_CACHE_HOME");
qputenv("XDG_CACHE_HOME", cache.path().toUtf8());
auto restoreCache = qScopeGuard([oldCache] { qputenv("XDG_CACHE_HOME", oldCache); QApplication::clipboard()->clear(); });
@ -127,24 +150,29 @@ private slots:
QCOMPARE(QApplication::clipboard()->text(), QString("keep on error"));
bool committed = false, received = false;
transferStarted = [&browser, &committed](mf_transfer_request transfer) {
QTimer::singleShot(50, &browser, [&browser, &committed, transfer] {
QFile file(QString::fromUtf8(transfer.local)); QVERIFY(file.open(QIODevice::WriteOnly));
QCOMPARE(file.write("drag bytes"), 10LL); file.close(); committed = true; complete(browser, transfer);
transferStarted = [&browser, &committed, dragStatus](mf_transfer_request transfer) {
QTimer::singleShot(50, &browser, [&browser, &committed, transfer, dragStatus] {
if (!dragStatus) {
QFile file(QString::fromUtf8(transfer.local)); QVERIFY(file.open(QIODevice::WriteOnly));
QCOMPARE(file.write("drag bytes"), 10LL); file.close();
}
committed = true;
if (dragStatus == MF_CANCELLED) cancelButton(browser)->click();
complete(browser, transfer, dragStatus);
});
};
QTimer receiver; receiver.setInterval(5);
connect(&receiver, &QTimer::timeout, &browser, [&] {
auto* drag = QCoreApplication::instance()->findChild<QDrag*>();
if (!drag || !drag->mimeData()) return;
receiver.stop(); auto* data = drag->mimeData();
DragReceiver receiver;
receiver.receive = [&](const QMimeData* data) {
QVERIFY(data->hasUrls()); QVERIFY(!committed);
// Запрос системного менеджера приходит до скачивания и возвращается лишь после commit.
auto urls = data->urls(); QVERIFY(committed); QCOMPARE(urls.size(), 1);
QFile file(urls.first().toLocalFile()); QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(file.readAll(), QByteArray("drag bytes"));
received = true; QDrag::cancel();
});
receiver.start();
auto urls = data->urls(); QVERIFY(committed);
if (!dragStatus) {
QCOMPARE(urls.size(), 1); QFile file(urls.first().toLocalFile());
QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(file.readAll(), QByteArray("drag bytes"));
} else QVERIFY(urls.isEmpty());
received = true;
};
QCoreApplication::instance()->installEventFilter(&receiver);
QTimer::singleShot(3000, &browser, [] { QDrag::cancel(); });
tree->setFocus(); QCoreApplication::processEvents(); QPoint point = tree->visualItemRect(item).center();
QTest::mousePress(tree->viewport(), Qt::LeftButton, Qt::NoModifier, point);

Loading…
Cancel
Save